Skip to content

Commit b0b0f91

Browse files
bincooobincooo
authored andcommitted
style(zed): add models
1 parent 7386986 commit b0b0f91

File tree

8 files changed

+502
-2
lines changed

8 files changed

+502
-2
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
/tmp/
2121
/plugins/
2222
node_modules/
23-
internal/plugin/llm/3rd/
23+
relay/3rd/
2424

2525
# Dependency directories (remove the comment below to include it)
2626
# vendor/

core/cache/memory.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ var (
2525
bingCacheManager *Manager[string]
2626
cursorCacheManager *Manager[string]
2727
qodoCacheManager *Manager[string]
28+
zedCacheManager *Manager[string]
2829
)
2930

3031
func init() {
@@ -53,6 +54,12 @@ func init() {
5354
qodoCacheManager = &Manager[string]{
5455
cache.New[string](gocacheStore.NewGoCache(client)),
5556
}
57+
58+
client = gocache.New(5*time.Minute, 5*time.Minute)
59+
zedCacheManager = &Manager[string]{
60+
cache.New[string](gocacheStore.NewGoCache(client)),
61+
}
62+
5663
})
5764
}
5865

@@ -76,6 +83,10 @@ func QodoCacheManager() *Manager[string] {
7683
return qodoCacheManager
7784
}
7885

86+
func ZedCacheManager() *Manager[string] {
87+
return zedCacheManager
88+
}
89+
7990
func (cacheManager *Manager[T]) SetValue(key string, value T) error {
8091
return cacheManager.SetWithExpiration(key, value, 120*time.Second)
8192
}

relay/llm/zed/adapter.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package zed
2+
3+
import (
4+
"chatgpt-adapter/core/common"
5+
"chatgpt-adapter/core/gin/inter"
6+
"chatgpt-adapter/core/gin/model"
7+
"chatgpt-adapter/core/gin/response"
8+
"chatgpt-adapter/core/logger"
9+
"github.com/gin-gonic/gin"
10+
"github.com/iocgo/sdk/env"
11+
)
12+
13+
var (
14+
Model = "zed"
15+
)
16+
17+
type api struct {
18+
inter.BaseAdapter
19+
20+
env *env.Environment
21+
}
22+
23+
func (api *api) Match(ctx *gin.Context, model string) (ok bool, err error) {
24+
if len(model) <= 4 || Model+"/" != model[:4] {
25+
return
26+
}
27+
slice := api.env.GetStringSlice("zed.model")
28+
for _, mod := range append(slice, []string{
29+
"claude-3-5-sonnet-latest",
30+
"claude-3-7-sonnet-latest",
31+
}...) {
32+
if model[4:] == mod {
33+
ok = true
34+
return
35+
}
36+
}
37+
return
38+
}
39+
40+
func (api *api) Models() (slice []model.Model) {
41+
for _, mod := range append(api.env.GetStringSlice("zed.model"), []string{
42+
"claude-3-5-sonnet-latest",
43+
"claude-3-7-sonnet-latest",
44+
}...) {
45+
slice = append(slice, model.Model{
46+
Id: Model + "/" + mod,
47+
Object: "model",
48+
Created: 1686935002,
49+
By: Model + "-adapter",
50+
})
51+
}
52+
return
53+
}
54+
55+
func (api *api) ToolChoice(ctx *gin.Context) (ok bool, err error) {
56+
var (
57+
cookie = ctx.GetString("token")
58+
proxied = api.env.GetString("server.proxied")
59+
completion = common.GetGinCompletion(ctx)
60+
)
61+
62+
if toolChoice(ctx, api.env, cookie, proxied, completion) {
63+
ok = true
64+
}
65+
return
66+
}
67+
68+
func (api *api) Completion(ctx *gin.Context) (err error) {
69+
var (
70+
cookie = ctx.GetString("token")
71+
proxied = api.env.GetString("server.proxied")
72+
completion = common.GetGinCompletion(ctx)
73+
)
74+
75+
request, err := convertRequest(completion)
76+
if err != nil {
77+
logger.Error(err)
78+
return
79+
}
80+
81+
r, err := fetch(ctx, api.env, proxied, cookie, request)
82+
if err != nil {
83+
logger.Error(err)
84+
return
85+
}
86+
87+
content := waitResponse(ctx, r, completion.Stream)
88+
if content == "" && response.NotResponse(ctx) {
89+
response.Error(ctx, -1, "EMPTY RESPONSE")
90+
}
91+
return
92+
}

relay/llm/zed/ctor.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package zed
2+
3+
import (
4+
"chatgpt-adapter/core/gin/inter"
5+
"github.com/iocgo/sdk/env"
6+
7+
_ "github.com/iocgo/sdk"
8+
)
9+
10+
// @Inject(name = "zed-adapter")
11+
func New(env *env.Environment) inter.Adapter {
12+
return &api{env: env}
13+
}

relay/llm/zed/fetch.go

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
package zed
2+
3+
import (
4+
"bytes"
5+
"chatgpt-adapter/core/cache"
6+
"chatgpt-adapter/core/common"
7+
"chatgpt-adapter/core/gin/model"
8+
"context"
9+
"errors"
10+
"fmt"
11+
"github.com/bincooo/emit.io"
12+
"github.com/gin-gonic/gin"
13+
"github.com/iocgo/sdk/env"
14+
"net/http"
15+
"strings"
16+
"time"
17+
)
18+
19+
var (
20+
userAgent = "Zed/0.178.5 (macos; x86_64)"
21+
)
22+
23+
type Float32 float32
24+
25+
func (f Float32) MarshalJSON() ([]byte, error) {
26+
return []byte(fmt.Sprintf("%.1f", f)), nil
27+
}
28+
29+
type zedRequest struct {
30+
Provider string `json:"provider"`
31+
Model string `json:"model"`
32+
ProviderRequest struct {
33+
Model string `json:"model"`
34+
MaxTokens int `json:"max_tokens"`
35+
Temperature Float32 `json:"temperature"`
36+
System string `json:"system"`
37+
Messages []model.Keyv[interface{}] `json:"messages"`
38+
} `json:"provider_request"`
39+
}
40+
41+
func fetch(ctx *gin.Context, env *env.Environment, proxied, cookie string, request zedRequest) (response *http.Response, err error) {
42+
token := env.GetString("zed.token")
43+
if token != "" {
44+
cookie = token
45+
if strings.HasPrefix(cookie, "http") {
46+
token, err = genToken(ctx.Request.Context(), token)
47+
if err != nil {
48+
return
49+
}
50+
cookie = token
51+
}
52+
}
53+
54+
response, err = emit.ClientBuilder(common.HTTPClient).
55+
Context(ctx.Request.Context()).
56+
Proxies(proxied).
57+
POST("https://llm.zed.dev/completion").
58+
JSONHeader().
59+
Header("accept", "*/*").
60+
Header("host", "llm.zed.dev").
61+
Header("user-agent", userAgent).
62+
Header("authorization", "Bearer "+cookie).
63+
Body(request).
64+
DoS(http.StatusOK)
65+
return
66+
}
67+
68+
func genToken(ctx context.Context, url string) (value string, err error) {
69+
manager := cache.ZedCacheManager()
70+
if value, _ = manager.GetValue(url); value != "" {
71+
return
72+
}
73+
74+
var resp *http.Response
75+
retry := 2
76+
label:
77+
retry--
78+
resp, err = emit.ClientBuilder(common.HTTPClient).
79+
Context(ctx).
80+
GET(url).DoS(http.StatusOK)
81+
if err != nil {
82+
return
83+
}
84+
defer resp.Body.Close()
85+
86+
value = emit.TextResponse(resp)
87+
if value == "" || !strings.HasPrefix(value, "Bearer ") {
88+
if retry > 0 {
89+
goto label
90+
}
91+
92+
err = errors.New("invalid token")
93+
return
94+
}
95+
value = value[7:]
96+
_ = manager.SetWithExpiration(url, value, time.Hour)
97+
return
98+
}
99+
100+
func convertRequest(completion model.Completion) (request zedRequest, err error) {
101+
contentBuffer := new(bytes.Buffer)
102+
customInstructions := ""
103+
104+
if len(completion.Messages) == 1 {
105+
contentBuffer.WriteString(completion.Messages[0].GetString("content"))
106+
goto label
107+
}
108+
109+
if len(completion.Messages) > 1 {
110+
message := completion.Messages[0]
111+
if message.Is("role", "system") {
112+
customInstructions = message.GetString("content")
113+
completion.Messages = completion.Messages[1:]
114+
}
115+
}
116+
117+
label:
118+
request = zedRequest{
119+
Provider: "anthropic",
120+
Model: completion.Model[4:],
121+
ProviderRequest: struct {
122+
Model string `json:"model"`
123+
MaxTokens int `json:"max_tokens"`
124+
Temperature Float32 `json:"temperature"`
125+
System string `json:"system"`
126+
Messages []model.Keyv[interface{}] `json:"messages"`
127+
}{
128+
Model: completion.Model[4:],
129+
MaxTokens: completion.MaxTokens,
130+
System: customInstructions,
131+
Messages: completion.Messages,
132+
Temperature: Float32(completion.Temperature),
133+
},
134+
}
135+
return
136+
}
137+
138+
func elseOf[T any](condition bool, t1, t2 T) T {
139+
if condition {
140+
return t1
141+
}
142+
return t2
143+
}

0 commit comments

Comments
 (0)