Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit1103e10

Browse files
committed
chore: add experiment agentic-chat, add tests for chat API routes
1 parentfb58caa commit1103e10

File tree

9 files changed

+153
-10
lines changed

9 files changed

+153
-10
lines changed

‎coderd/apidoc/docs.go

Lines changed: 5 additions & 2 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/apidoc/swagger.json

Lines changed: 5 additions & 2 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/chat.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -161,16 +161,18 @@ func (api *API) postChatMessages(w http.ResponseWriter, r *http.Request) {
161161
return
162162
}
163163

164-
messages:=make([]aisdk.Message,0,len(dbMessages))
165-
fori,message:=rangedbMessages {
166-
err=json.Unmarshal(message.Content,&messages[i])
164+
messages:=make([]codersdk.ChatMessage,0)
165+
for_,dbMsg:=rangedbMessages {
166+
varmsg codersdk.ChatMessage
167+
err=json.Unmarshal(dbMsg.Content,&msg)
167168
iferr!=nil {
168169
httpapi.Write(ctx,w,http.StatusInternalServerError, codersdk.Response{
169170
Message:"Failed to unmarshal chat message",
170171
Detail:err.Error(),
171172
})
172173
return
173174
}
175+
messages=append(messages,msg)
174176
}
175177
messages=append(messages,req.Message)
176178

@@ -180,8 +182,8 @@ func (api *API) postChatMessages(w http.ResponseWriter, r *http.Request) {
180182
tools:=make([]aisdk.Tool,len(toolsdk.All))
181183
handlers:=map[string]toolsdk.GenericHandlerFunc{}
182184
fori,tool:=rangetoolsdk.All {
183-
iftool.Tool.Schema.Required==nil {
184-
tool.Tool.Schema.Required= []string{}
185+
iftool.Name=="coder_report_task" {
186+
continue// Thistool requires an agent to run.
185187
}
186188
tools[i]=tool.Tool
187189
handlers[tool.Tool.Name]=tool.Handler

‎coderd/chat_test.go

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package coderd_test
2+
3+
import (
4+
"net/http"
5+
"strings"
6+
"testing"
7+
"time"
8+
9+
"github.com/stretchr/testify/require"
10+
11+
"github.com/coder/coder/v2/coderd/coderdtest"
12+
"github.com/coder/coder/v2/coderd/database"
13+
"github.com/coder/coder/v2/coderd/database/dbgen"
14+
"github.com/coder/coder/v2/coderd/database/dbtime"
15+
"github.com/coder/coder/v2/codersdk"
16+
"github.com/coder/coder/v2/testutil"
17+
)
18+
19+
funcTestChat(t*testing.T) {
20+
t.Parallel()
21+
22+
t.Run("ExperimentAgenticChatDisabled",func(t*testing.T) {
23+
t.Parallel()
24+
25+
client,_:=coderdtest.NewWithDatabase(t,nil)
26+
owner:=coderdtest.CreateFirstUser(t,client)
27+
memberClient,_:=coderdtest.CreateAnotherUser(t,client,owner.OrganizationID)
28+
29+
// Hit the endpoint to get the chat. It should return a 404.
30+
ctx:=testutil.Context(t,testutil.WaitShort)
31+
_,err:=memberClient.ListChats(ctx)
32+
require.Error(t,err,"list chats should fail")
33+
varsdkErr*codersdk.Error
34+
require.ErrorAs(t,err,&sdkErr,"request should fail with an SDK error")
35+
require.Equal(t,http.StatusForbidden,sdkErr.StatusCode())
36+
})
37+
38+
t.Run("ChatCRUD",func(t*testing.T) {
39+
t.Parallel()
40+
41+
dv:=coderdtest.DeploymentValues(t)
42+
dv.Experiments= []string{string(codersdk.ExperimentAgenticChat)}
43+
dv.AI.Value= codersdk.AIConfig{
44+
Providers: []codersdk.AIProviderConfig{
45+
{
46+
Type:"fake",
47+
APIKey:"",
48+
BaseURL:"http://localhost",
49+
Models: []string{"fake-model"},
50+
},
51+
},
52+
}
53+
client,db:=coderdtest.NewWithDatabase(t,&coderdtest.Options{
54+
DeploymentValues:dv,
55+
})
56+
owner:=coderdtest.CreateFirstUser(t,client)
57+
memberClient,memberUser:=coderdtest.CreateAnotherUser(t,client,owner.OrganizationID)
58+
59+
// Seed the database with some data.
60+
dbChat:=dbgen.Chat(t,db, database.Chat{
61+
OwnerID:memberUser.ID,
62+
CreatedAt:dbtime.Now().Add(-time.Hour),
63+
UpdatedAt:dbtime.Now().Add(-time.Hour),
64+
Title:"This is a test chat",
65+
})
66+
_=dbgen.ChatMessage(t,db, database.ChatMessage{
67+
ChatID:dbChat.ID,
68+
CreatedAt:dbtime.Now().Add(-time.Hour),
69+
Content: []byte(`[{"content": "Hello world"}]`),
70+
Model:"fake model",
71+
Provider:"fake",
72+
})
73+
74+
ctx:=testutil.Context(t,testutil.WaitShort)
75+
76+
// Listing chats should return the chat we just inserted.
77+
chats,err:=memberClient.ListChats(ctx)
78+
require.NoError(t,err,"list chats should succeed")
79+
require.Len(t,chats,1,"response should have one chat")
80+
require.Equal(t,dbChat.ID,chats[0].ID,"unexpected chat ID")
81+
require.Equal(t,dbChat.Title,chats[0].Title,"unexpected chat title")
82+
require.Equal(t,dbChat.CreatedAt.UTC(),chats[0].CreatedAt.UTC(),"unexpected chat created at")
83+
require.Equal(t,dbChat.UpdatedAt.UTC(),chats[0].UpdatedAt.UTC(),"unexpected chat updated at")
84+
85+
// Fetching a single chat by ID should return the same chat.
86+
chat,err:=memberClient.Chat(ctx,dbChat.ID)
87+
require.NoError(t,err,"get chat should succeed")
88+
require.Equal(t,chats[0],chat,"get chat should return the same chat")
89+
90+
// Listing chat messages should return the message we just inserted.
91+
messages,err:=memberClient.ChatMessages(ctx,dbChat.ID)
92+
require.NoError(t,err,"list chat messages should succeed")
93+
require.Len(t,messages,1,"response should have one message")
94+
require.Equal(t,"Hello world",messages[0].Content,"response should have the correct message content")
95+
96+
// Creating a new chat will fail because the model does not exist.
97+
// TODO: Test the message streaming functionality with a mock model.
98+
// Inserting a chat message will fail due to the model not existing.
99+
_,err=memberClient.CreateChatMessage(ctx,dbChat.ID, codersdk.CreateChatMessageRequest{
100+
Model:"echo",
101+
Message: codersdk.ChatMessage{
102+
Role:"user",
103+
Content:"Hello world",
104+
},
105+
Thinking:false,
106+
})
107+
require.Error(t,err,"create chat message should fail")
108+
varsdkErr*codersdk.Error
109+
require.ErrorAs(t,err,&sdkErr,"create chat should fail with an SDK error")
110+
require.Equal(t,http.StatusBadRequest,sdkErr.StatusCode(),"create chat should fail with a 400 when model does not exist")
111+
112+
// Creating a new chat message with malformed content should fail.
113+
res,err:=memberClient.Request(ctx,http.MethodPost,"/api/v2/chats/"+dbChat.ID.String()+"/messages",strings.NewReader(`{malformed json}`))
114+
require.NoError(t,err)
115+
deferres.Body.Close()
116+
apiErr:=codersdk.ReadBodyAsError(res)
117+
require.Contains(t,apiErr.Error(),"Failed to decode chat message")
118+
119+
_,err=memberClient.CreateChat(ctx)
120+
require.NoError(t,err,"create chat should succeed")
121+
chats,err=memberClient.ListChats(ctx)
122+
require.NoError(t,err,"list chats should succeed")
123+
require.Len(t,chats,2,"response should have two chats")
124+
})
125+
}

‎coderd/coderd.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1001,8 +1001,12 @@ func New(options *Options) *API {
10011001
r.Get("/{fileID}",api.fileByID)
10021002
r.Post("/",api.postFile)
10031003
})
1004+
// Chats are an experimental feature
10041005
r.Route("/chats",func(r chi.Router) {
1005-
r.Use(apiKeyMiddleware)
1006+
r.Use(
1007+
apiKeyMiddleware,
1008+
httpmw.RequireExperiment(api.Experiments,codersdk.ExperimentAgenticChat),
1009+
)
10061010
r.Get("/",api.listChats)
10071011
r.Post("/",api.postChats)
10081012
r.Route("/{chat}",func(r chi.Router) {

‎codersdk/chat.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ func (c *Client) ListChats(ctx context.Context) ([]Chat, error) {
4040
returnnil,xerrors.Errorf("execute request: %w",err)
4141
}
4242
deferres.Body.Close()
43+
ifres.StatusCode!=http.StatusOK {
44+
returnnil,ReadBodyAsError(res)
45+
}
4346

4447
varchats []Chat
4548
returnchats,json.NewDecoder(res.Body).Decode(&chats)

‎codersdk/deployment.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3328,6 +3328,7 @@ const (
33283328
ExperimentWebPushExperiment="web-push"// Enables web push notifications through the browser.
33293329
ExperimentDynamicParametersExperiment="dynamic-parameters"// Enables dynamic parameters when creating a workspace.
33303330
ExperimentWorkspacePrebuildsExperiment="workspace-prebuilds"// Enables the new workspace prebuilds feature.
3331+
ExperimentAgenticChatExperiment="agentic-chat"// Enables the new agentic AI chat feature.
33313332
)
33323333

33333334
// ExperimentsSafe should include all experiments that are safe for

‎docs/reference/api/schemas.md

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎site/src/api/typesGenerated.ts

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp