|
| 1 | +package coderd |
| 2 | + |
| 3 | +import ( |
| 4 | +"net/http" |
| 5 | + |
| 6 | +"github.com/coder/coder/v2/coderd/database" |
| 7 | +"github.com/coder/coder/v2/coderd/httpapi" |
| 8 | +"github.com/coder/coder/v2/coderd/rbac" |
| 9 | +"github.com/coder/coder/v2/coderd/rbac/policy" |
| 10 | +"github.com/coder/coder/v2/codersdk" |
| 11 | +) |
| 12 | + |
| 13 | +const ( |
| 14 | +maxListInterceptionsLimit=1000 |
| 15 | +defaultListInterceptionsLimit=100 |
| 16 | +) |
| 17 | + |
| 18 | +func (api*API)aiBridgeListInterceptions(rw http.ResponseWriter,r*http.Request) { |
| 19 | +if!api.Authorize(r,policy.ActionRead,rbac.ResourceAibridgeInterception) { |
| 20 | +httpapi.Forbidden(rw) |
| 21 | +return |
| 22 | +} |
| 23 | + |
| 24 | +ctx:=r.Context() |
| 25 | +varreq codersdk.AIBridgeListInterceptionsRequest |
| 26 | +if!httpapi.Read(ctx,rw,r,&req) { |
| 27 | +return |
| 28 | +} |
| 29 | + |
| 30 | +if!req.PeriodStart.IsZero()&&!req.PeriodEnd.IsZero()&&req.PeriodEnd.Before(req.PeriodStart) { |
| 31 | +httpapi.Write(ctx,rw,http.StatusBadRequest, codersdk.Response{ |
| 32 | +Message:"Invalid time frame.", |
| 33 | +Detail:"End of the search period must be before start.", |
| 34 | +}) |
| 35 | +return |
| 36 | +} |
| 37 | + |
| 38 | +ifreq.Limit==0 { |
| 39 | +req.Limit=defaultListInterceptionsLimit |
| 40 | +} |
| 41 | + |
| 42 | +ifreq.Limit>maxListInterceptionsLimit||req.Limit<1 { |
| 43 | +httpapi.Write(ctx,rw,http.StatusBadRequest, codersdk.Response{ |
| 44 | +Message:"Invalid limit value.", |
| 45 | +Detail:"Limit value must be in range <1, 1000>", |
| 46 | +}) |
| 47 | +return |
| 48 | +} |
| 49 | + |
| 50 | +// Database returns one row for each tuple (interception, tool, prompt). |
| 51 | +// Right now there is a single promp per interception although model allows multiple so this could change in the future. |
| 52 | +// There can be multiple tools used in single interception. |
| 53 | +// Results are ordered by Interception.StartedAt, Interception.ID, Tool.CreatedAt |
| 54 | +rows,err:=api.Database.ListAIBridgeInterceptions(ctx, database.ListAIBridgeInterceptionsParams{ |
| 55 | +PeriodStart:req.PeriodStart, |
| 56 | +PeriodEnd:req.PeriodEnd, |
| 57 | +CursorTime:req.Cursor.Time, |
| 58 | +CursorID:req.Cursor.ID, |
| 59 | +InitiatorID:req.InitiatorID, |
| 60 | +LimitOpt:req.Limit, |
| 61 | +}) |
| 62 | +iferr!=nil { |
| 63 | +httpapi.Write(ctx,rw,http.StatusInternalServerError, codersdk.Response{ |
| 64 | +Message:"Internal error getting AIBridge interceptions.", |
| 65 | +Detail:err.Error(), |
| 66 | +}) |
| 67 | +return |
| 68 | +} |
| 69 | + |
| 70 | +resp:=prepareResponse(rows) |
| 71 | +httpapi.Write(ctx,rw,http.StatusOK,resp) |
| 72 | +} |
| 73 | + |
| 74 | +funcprepareResponse(rows []database.ListAIBridgeInterceptionsRow) codersdk.AIBridgeListInterceptionsResponse { |
| 75 | +resp:= codersdk.AIBridgeListInterceptionsResponse{ |
| 76 | +Results: []codersdk.AIBridgeListInterceptionsResult{}, |
| 77 | +} |
| 78 | + |
| 79 | +iflen(rows)>0 { |
| 80 | +resp.Cursor.ID=rows[len(rows)-1].ID |
| 81 | +resp.Cursor.Time=rows[len(rows)-1].StartedAt.UTC() |
| 82 | +} |
| 83 | + |
| 84 | +fori:=0;i<len(rows); { |
| 85 | +row:=rows[i] |
| 86 | +row.StartedAt=row.StartedAt.UTC() |
| 87 | + |
| 88 | +result:= codersdk.AIBridgeListInterceptionsResult{ |
| 89 | +InterceptionID:row.ID, |
| 90 | +UserID:row.InitiatorID, |
| 91 | +Provider:row.Provider, |
| 92 | +Model:row.Model, |
| 93 | +Prompt:row.Prompt.String, |
| 94 | +StartedAt:row.StartedAt, |
| 95 | +Tokens: codersdk.AIBridgeListInterceptionsTokens{ |
| 96 | +Input:row.InputTokens, |
| 97 | +Output:row.OutputTokens, |
| 98 | +}, |
| 99 | +Tools: []codersdk.AIBridgeListInterceptionsTool{}, |
| 100 | +} |
| 101 | + |
| 102 | +interceptionID:=row.ID |
| 103 | +for ;i<len(rows)&&interceptionID==rows[i].ID;i++ { |
| 104 | +ifrows[i].ServerUrl.Valid||rows[i].Tool.Valid||rows[i].Input.Valid { |
| 105 | +result.Tools=append(result.Tools, codersdk.AIBridgeListInterceptionsTool{ |
| 106 | +Server:rows[i].ServerUrl.String, |
| 107 | +Tool:rows[i].Tool.String, |
| 108 | +Input:rows[i].Input.String, |
| 109 | +}) |
| 110 | +} |
| 111 | +} |
| 112 | + |
| 113 | +resp.Results=append(resp.Results,result) |
| 114 | +} |
| 115 | +returnresp |
| 116 | +} |