Skip to content

Commit 0788f09

Browse files
committed
feat: define ResponsesModel component interface
1 parent adf4b1b commit 0788f09

File tree

6 files changed

+653
-5
lines changed

6 files changed

+653
-5
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright 2025 CloudWeGo Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package responses
18+
19+
import (
20+
"github.com/cloudwego/eino/callbacks"
21+
"github.com/cloudwego/eino/schema"
22+
)
23+
24+
// TokenUsageMeta is the token usage for the model.
25+
type TokenUsageMeta struct {
26+
InputTokens int64 `json:"input_tokens"`
27+
InputTokensDetails InputTokensUsageDetails `json:"input_tokens_details"`
28+
OutputTokens int64 `json:"output_tokens"`
29+
OutputTokensDetails OutputTokensUsageDetails `json:"output_tokens_details"`
30+
TotalTokens int64 `json:"total_tokens"`
31+
}
32+
33+
type InputTokensUsageDetails struct {
34+
CachedTokens int64 `json:"cached_tokens"`
35+
}
36+
37+
type OutputTokensUsageDetails struct {
38+
ReasoningTokens int64 `json:"reasoning_tokens"`
39+
}
40+
41+
// Config is the config for the model.
42+
type Config struct {
43+
// Model is the model name.
44+
Model string
45+
// Temperature is the temperature, which controls the randomness of the model.
46+
Temperature float32
47+
// TopP is the top p, which controls the diversity of the model.
48+
TopP float32
49+
}
50+
51+
// CallbackInput is the input for the model callback.
52+
type CallbackInput struct {
53+
// Responses is the responses to be sent to the model.
54+
Responses []*schema.Response
55+
// Tools is the tools to be used in the model.
56+
Tools []*schema.ToolInfo
57+
// Config is the config for the model.
58+
Config *Config
59+
// Extra is the extra information for the callback.
60+
Extra map[string]any
61+
}
62+
63+
// CallbackOutput is the output for the model callback.
64+
type CallbackOutput struct {
65+
// Response is the response generated by the model.
66+
Response *schema.Response
67+
// Config is the config for the model.
68+
Config *Config
69+
// Usage is the token usage of this request.
70+
Usage *TokenUsageMeta
71+
// Extra is the extra information for the callback.
72+
Extra map[string]any
73+
}
74+
75+
// ConvCallbackInput converts the callback input to the model callback input.
76+
func ConvCallbackInput(src callbacks.CallbackInput) *CallbackInput {
77+
switch t := src.(type) {
78+
case *CallbackInput: // when callback is triggered within component implementation, the input is usually already a typed *model.CallbackInput
79+
return t
80+
case []*schema.Response: // when callback is injected by graph node, not the component implementation itself, the input is the input of Chat Model interface, which is []*schema.Message
81+
return &CallbackInput{
82+
Responses: t,
83+
}
84+
default:
85+
return nil
86+
}
87+
}
88+
89+
// ConvCallbackOutput converts the callback output to the model callback output.
90+
func ConvCallbackOutput(src callbacks.CallbackOutput) *CallbackOutput {
91+
switch t := src.(type) {
92+
case *CallbackOutput: // when callback is triggered within component implementation, the output is usually already a typed *model.CallbackOutput
93+
return t
94+
case *schema.Response: // when callback is injected by graph node, not the component implementation itself, the output is the output of Chat Model interface, which is *schema.Message
95+
return &CallbackOutput{
96+
Response: t,
97+
}
98+
default:
99+
return nil
100+
}
101+
}

components/responses/interface.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2025 CloudWeGo Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package responses
18+
19+
import (
20+
"context"
21+
22+
"github.com/cloudwego/eino/schema"
23+
)
24+
25+
type BaseResponsesModel interface {
26+
Generate(ctx context.Context, input []*schema.Response, opts ...Option) (*schema.Response, error)
27+
Stream(ctx context.Context, input []*schema.Response, opts ...Option) (*schema.StreamReader[*schema.Response], error)
28+
}
29+
30+
type ToolCallingResponsesModel interface {
31+
BaseResponsesModel
32+
33+
WithTools(tools []*schema.ToolInfo) (ToolCallingResponsesModel, error)
34+
}

components/responses/option.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright 2025 CloudWeGo Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package responses
18+
19+
// Options is the common options for the model.
20+
type Options struct {
21+
}
22+
23+
// Option is the call option for ChatModel component.
24+
type Option struct {
25+
apply func(opts *Options)
26+
27+
implSpecificOptFn any
28+
}
29+
30+
// WrapImplSpecificOptFn is the option to wrap the implementation specific option function.
31+
func WrapImplSpecificOptFn[T any](optFn func(*T)) Option {
32+
return Option{
33+
implSpecificOptFn: optFn,
34+
}
35+
}
36+
37+
// GetCommonOptions extract model Options from Option list, optionally providing a base Options with default values.
38+
func GetCommonOptions(base *Options, opts ...Option) *Options {
39+
if base == nil {
40+
base = &Options{}
41+
}
42+
43+
for i := range opts {
44+
opt := opts[i]
45+
if opt.apply != nil {
46+
opt.apply(base)
47+
}
48+
}
49+
50+
return base
51+
}
52+
53+
// GetImplSpecificOptions extract the implementation specific options from Option list, optionally providing a base options with default values.
54+
// e.g.
55+
//
56+
// myOption := &MyOption{
57+
// Field1: "default_value",
58+
// }
59+
//
60+
// myOption := model.GetImplSpecificOptions(myOption, opts...)
61+
func GetImplSpecificOptions[T any](base *T, opts ...Option) *T {
62+
if base == nil {
63+
base = new(T)
64+
}
65+
66+
for i := range opts {
67+
opt := opts[i]
68+
if opt.implSpecificOptFn != nil {
69+
optFn, ok := opt.implSpecificOptFn.(func(*T))
70+
if ok {
71+
optFn(base)
72+
}
73+
}
74+
}
75+
76+
return base
77+
}

go.mod

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
module github.com/cloudwego/eino
22

3-
go 1.18
3+
go 1.24
44

55
require (
6+
github.com/anthropics/anthropic-sdk-go v1.16.0
67
github.com/bytedance/sonic v1.14.1
78
github.com/eino-contrib/jsonschema v1.0.2
89
github.com/getkin/kin-openapi v0.118.0
910
github.com/google/uuid v1.6.0
1011
github.com/nikolalohinski/gonja v1.5.3
12+
github.com/openai/openai-go/v2 v2.7.1
1113
github.com/slongfield/pyfmt v0.0.0-20220222012616-ea85ff4c361f
1214
github.com/smartystreets/goconvey v1.8.1
1315
github.com/stretchr/testify v1.10.0
@@ -42,11 +44,15 @@ require (
4244
github.com/pmezard/go-difflib v1.0.0 // indirect
4345
github.com/sirupsen/logrus v1.9.3 // indirect
4446
github.com/smarty/assertions v1.15.0 // indirect
47+
github.com/tidwall/gjson v1.18.0 // indirect
48+
github.com/tidwall/match v1.1.1 // indirect
49+
github.com/tidwall/pretty v1.2.1 // indirect
50+
github.com/tidwall/sjson v1.2.5 // indirect
4551
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
4652
github.com/yargevad/filepathx v1.0.0 // indirect
4753
golang.org/x/arch v0.11.0 // indirect
4854
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect
49-
golang.org/x/sys v0.26.0 // indirect
55+
golang.org/x/sys v0.34.0 // indirect
5056
gopkg.in/yaml.v2 v2.4.0 // indirect
5157
gopkg.in/yaml.v3 v3.0.1 // indirect
5258
)

go.sum

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
github.com/airbrake/gobrake v3.6.1+incompatible/go.mod h1:wM4gu3Cn0W0K7GUuVWnlXZU11AGBXMILnrdOU8Kn00o=
2+
github.com/anthropics/anthropic-sdk-go v1.16.0 h1:nRkOFDqYXsHteoIhjdJr/5dsiKbFF3rflSv8ax50y8o=
3+
github.com/anthropics/anthropic-sdk-go v1.16.0/go.mod h1:WTz31rIUHUHqai2UslPpw5CwXrQP3geYBioRV4WOLvE=
24
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
35
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
46
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
@@ -28,6 +30,7 @@ github.com/getkin/kin-openapi v0.118.0 h1:z43njxPmJ7TaPpMSCQb7PN0dEYno4tyBPQcrFd
2830
github.com/getkin/kin-openapi v0.118.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc=
2931
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
3032
github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI=
33+
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
3134
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
3235
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
3336
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
@@ -67,8 +70,11 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN
6770
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
6871
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
6972
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
73+
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
7074
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
75+
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
7176
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
77+
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
7278
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
7379
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
7480
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -81,6 +87,8 @@ github.com/nikolalohinski/gonja v1.5.3/go.mod h1:RmjwxNiXAEqcq1HeK5SSMmqFJvKOfTf
8187
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
8288
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
8389
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
90+
github.com/openai/openai-go/v2 v2.7.1 h1:/tfvTJhfv7hTSL8mWwc5VL4WLLSDL5yn9VqVykdu9r8=
91+
github.com/openai/openai-go/v2 v2.7.1/go.mod h1:jrJs23apqJKKbT+pqtFgNKpRju/KP9zpUTZhz3GElQE=
8492
github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
8593
github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
8694
github.com/perimeterx/marshmallow v1.1.4 h1:pZLDH9RjlLGGorbXhcaQLhfuV0pFMNfPO55FuFkxqLw=
@@ -113,6 +121,16 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
113121
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
114122
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
115123
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
124+
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
125+
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
126+
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
127+
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
128+
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
129+
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
130+
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
131+
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
132+
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
133+
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
116134
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
117135
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
118136
github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo=
@@ -122,24 +140,27 @@ github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95
122140
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
123141
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
124142
github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg=
143+
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
125144
github.com/yargevad/filepathx v1.0.0 h1:SYcT+N3tYGi+NvazubCNlvgIPbzAk7i7y2dwg3I5FYc=
126145
github.com/yargevad/filepathx v1.0.0/go.mod h1:BprfX/gpYNJHJfc35GjRRpVcwWXS89gGulUIU5tK3tA=
127146
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
128147
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
129148
golang.org/x/arch v0.11.0 h1:KXV8WWKCXm6tRpLirl2szsO5j/oOODwZf4hATmGVNs4=
130149
golang.org/x/arch v0.11.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
131150
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
132-
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
151+
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
152+
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
133153
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw=
134154
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
135155
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
136156
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
137157
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
138158
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
139159
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
140-
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
141-
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
160+
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
161+
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
142162
golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
163+
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
143164
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
144165
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
145166
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=

0 commit comments

Comments
 (0)