feat/API: implement /models and /models/{modelId} using TypeSpec (#64421)

Fixes CODY-3085
Fixes CODY-3086

Previously, there was no way for OpenAI clients to list the available
models on Sourcegraph or query metadata about a given model ID ("model
ref" using our internal terminology). This PR fixes that problem AND
additionally adds infrastructure to auto-generate Go models from a
TypeSpec specification.

[TypeSpec](https://typespec.io/) is an IDL to document REST APIs,
created by Microsoft. Historically, the Go code in this repository has
been the single source of truth about what exact JSON structures are
expected in HTTP request/response pairs in our REST endpoints. This new
TypeSpec infrastructure allows us to document these shapes at a higher
abstraction level, which has several benefits including automatic
OpenAPI generation, which we can use to generate docs on
sourcegraph.com/docs or automatically generate client bindings in
TypeScript (among many other use-cases).

I am planning to write an RFC to propose we start using TypeSpec for new
REST endpoints going forward. If the RFC is not approved then we can
just delete the new `tools/typespec_codegen` directory and keep the
generated code in the repo. It won't be a big difference in the end
compared our current manual approach of writing Go structs for HTTP
APIs.

<!-- PR description tips:
https://www.notion.so/sourcegraph/Write-a-good-pull-request-description-610a7fd3e613496eb76f450db5a49b6e
-->

## Test plan
See test cases. I additionally wrote a basic python script with the
official OpenAI client to test that it works with this endpoint. First,
I ran `sg start minimal`. Then I wrote this script
```py
import os
from openai import OpenAI
from dotenv import load_dotenv
import httpx

load_dotenv()

openai = OpenAI(
    # base_url="https://api.openai.com/v1",
    # api_key=os.getenv("OPENAI_API_KEY"),
    base_url="https://sourcegraph.test:3443/api/v1",
    api_key=os.getenv("SRC_ACCESS_TOKEN"),
    http_client=httpx.Client(verify=False)
)

def main():
    response = openai.models.list()
    for model in response.data:
        print(model.id)
if __name__ == "__main__":
    main()

```
Finally, I ran 
```
❯ python3 models.py
anthropic::unknown::claude-3-haiku-20240307
anthropic::unknown::claude-3-sonnet-20240229
fireworks::unknown::starcoder
```
<!-- REQUIRED; info at
https://docs-legacy.sourcegraph.com/dev/background-information/testing_principles
-->

## Changelog

* New `GET /.api/llm/models` and `GET /.api/llm/models/{modelId}` REST
API endpoints to list available LLM models on the instance and to get
information about a given model. This endpoints is compatible with the
`/models` and `/models/{modelId}` endpoints from OpenAI.

<!-- OPTIONAL; info at
https://www.notion.so/sourcegraph/Writing-a-changelog-entry-dd997f411d524caabf0d8d38a24a878c
-->
This commit is contained in:
Ólafur Páll Geirsson 2024-08-14 12:47:00 +02:00 committed by GitHub
parent c222523fa5
commit 1b1229c867
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 1088 additions and 77 deletions

View File

@ -26,6 +26,7 @@ client/web/node_modules
client/web-sveltekit/node_modules
client/wildcard/node_modules
internal/appliance/frontend/maintenance/node_modules
internal/openapi/node_modules
cmd/symbols/internal/squirrel/test_repos/starlark

View File

@ -4,8 +4,9 @@ load("//dev:go_defs.bzl", "go_test")
go_library(
name = "llmapi",
srcs = [
"chat_completions_handler.go",
"chat_completions_models.go",
"handler_chat_completions.go",
"handler_models.go",
"handler_models_modelid.go",
"httpapi.go",
],
importpath = "github.com/sourcegraph/sourcegraph/cmd/frontend/internal/llmapi",
@ -13,6 +14,7 @@ go_library(
deps = [
"//internal/completions/types",
"//internal/modelconfig/types",
"//internal/openapi/goapi",
"//lib/errors",
"@com_github_google_uuid//:uuid",
"@com_github_gorilla_mux//:mux",
@ -23,8 +25,9 @@ go_library(
go_test(
name = "llmapi_test",
srcs = [
"chat_completions_handler_test.go",
"chat_completions_models_test.go",
"handler_chat_completions_test.go",
"handler_models_modelid_test.go",
"handler_models_test.go",
"utils_test.go",
],
data = glob(["golly-recordings/**"]),
@ -33,8 +36,10 @@ go_test(
"//internal/golly",
"//internal/httpcli",
"//internal/modelconfig/types",
"//internal/openapi/goapi",
"@com_github_gorilla_mux//:mux",
"@com_github_hexops_autogold_v2//:autogold",
"@com_github_stretchr_testify//assert",
"@com_github_stretchr_testify//require",
],
)

View File

@ -11,13 +11,13 @@ import (
"time"
"github.com/google/uuid"
"github.com/sourcegraph/log"
sglog "github.com/sourcegraph/log"
"github.com/sourcegraph/sourcegraph/lib/errors"
completions "github.com/sourcegraph/sourcegraph/internal/completions/types"
types "github.com/sourcegraph/sourcegraph/internal/modelconfig/types"
"github.com/sourcegraph/sourcegraph/internal/openapi/goapi"
)
// chatCompletionsHandler implements the REST endpoint /chat/completions
@ -34,12 +34,10 @@ type chatCompletionsHandler struct {
GetModelConfig GetModelConfigurationFunc
}
type GetModelConfigurationFunc func() (*types.ModelConfiguration, error)
var _ http.Handler = (*chatCompletionsHandler)(nil)
func (h *chatCompletionsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var chatCompletionRequest CreateChatCompletionRequest
var chatCompletionRequest goapi.CreateChatCompletionRequest
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, fmt.Sprintf("io.ReadAll: %v", err), http.StatusInternalServerError)
@ -78,19 +76,14 @@ func (h *chatCompletionsHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques
chatCompletionResponse := transformToOpenAIResponse(sgResp, chatCompletionRequest)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
if err = json.NewEncoder(w).Encode(chatCompletionResponse); err != nil {
h.logger.Error("writing /chat/completions response body", log.Error(err))
}
serveJSON(w, r, h.logger, chatCompletionResponse)
}
// validateRequestedModel checks that are only use the modelref syntax
// (${ProviderID}::${APIVersionID}::${ModelID}). If the user passes the old
// syntax `${ProviderID}/${ModelID}`, then we try to return a helpful error
// message suggesting to use the new modelref syntax.
func validateRequestedModel(chatCompletionRequest CreateChatCompletionRequest, modelConfig *types.ModelConfiguration) string {
func validateRequestedModel(chatCompletionRequest goapi.CreateChatCompletionRequest, modelConfig *types.ModelConfiguration) string {
closestModelRef := ""
for _, model := range modelConfig.Models {
if string(model.ModelRef) == chatCompletionRequest.Model {
@ -109,7 +102,7 @@ func validateRequestedModel(chatCompletionRequest CreateChatCompletionRequest, m
return fmt.Sprintf("model %s is not supported%s", chatCompletionRequest.Model, didYouMean)
}
func validateChatCompletionRequest(chatCompletionRequest CreateChatCompletionRequest) string {
func validateChatCompletionRequest(chatCompletionRequest goapi.CreateChatCompletionRequest) string {
if chatCompletionRequest.N != nil && *chatCompletionRequest.N != 1 {
return "n must be nil or 1"
@ -148,7 +141,7 @@ func validateChatCompletionRequest(chatCompletionRequest CreateChatCompletionReq
return ""
}
func transformToSGRequest(openAIReq CreateChatCompletionRequest) completions.CodyCompletionRequestParameters {
func transformToSGRequest(openAIReq goapi.CreateChatCompletionRequest) completions.CodyCompletionRequestParameters {
maxTokens := 16 // Default in OpenAI openapi.yaml spec
if openAIReq.MaxTokens != nil {
maxTokens = *openAIReq.MaxTokens
@ -178,7 +171,7 @@ func transformToSGRequest(openAIReq CreateChatCompletionRequest) completions.Cod
}
}
func transformMessages(messages []ChatCompletionRequestMessage) []completions.Message {
func transformMessages(messages []goapi.ChatCompletionRequestMessage) []completions.Message {
// Transform OpenAI messages to Sourcegraph format
transformed := make([]completions.Message, len(messages))
for i, msg := range messages {
@ -248,23 +241,23 @@ func (h *chatCompletionsHandler) forwardToAPIHandler(sgReq completions.CodyCompl
return &sgResp, nil
}
func transformToOpenAIResponse(sgResp *completions.CompletionResponse, openAIReq CreateChatCompletionRequest) CreateChatCompletionResponse {
return CreateChatCompletionResponse{
func transformToOpenAIResponse(sgResp *completions.CompletionResponse, openAIReq goapi.CreateChatCompletionRequest) goapi.CreateChatCompletionResponse {
return goapi.CreateChatCompletionResponse{
ID: "chat-" + generateUUID(),
Object: "chat.completion",
Created: time.Now().Unix(),
Model: openAIReq.Model,
Choices: []ChatCompletionChoice{
Choices: []goapi.ChatCompletionChoice{
{
Index: 0,
Message: ChatCompletionResponseMessage{
Message: goapi.ChatCompletionResponseMessage{
Role: "assistant",
Content: sgResp.Completion,
},
FinishReason: sgResp.StopReason,
},
},
Usage: CompletionUsage{},
Usage: goapi.CompletionUsage{},
}
}

View File

@ -10,6 +10,7 @@ import (
"github.com/stretchr/testify/assert"
types "github.com/sourcegraph/sourcegraph/internal/modelconfig/types"
"github.com/sourcegraph/sourcegraph/internal/openapi/goapi"
)
func TestChatCompletionsHandler(t *testing.T) {
@ -89,7 +90,7 @@ func TestChatCompletionsHandler(t *testing.T) {
t.Fatalf("Expected status code %d, got %d. Body: %s%s", http.StatusOK, rr.Code, rr.Body.String(), extraMessage)
}
var resp CreateChatCompletionResponse
var resp goapi.CreateChatCompletionResponse
responseBytes := rr.Body.Bytes()
err := json.Unmarshal(responseBytes, &resp)
if err != nil {

View File

@ -0,0 +1,41 @@
package llmapi
import (
"fmt"
"net/http"
sglog "github.com/sourcegraph/log"
"github.com/sourcegraph/sourcegraph/internal/openapi/goapi"
)
type modelsHandler struct {
logger sglog.Logger
GetModelConfig GetModelConfigurationFunc
}
var _ http.Handler = (*modelsHandler)(nil)
func (m *modelsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
currentModelConfig, err := m.GetModelConfig()
if err != nil {
http.Error(w, fmt.Sprintf("modelConfigSvc.Get: %v", err), http.StatusInternalServerError)
return
}
var data []goapi.Model
for _, model := range currentModelConfig.Models {
data = append(data, goapi.Model{
Object: "model",
Id: string(model.ModelRef),
OwnedBy: string(model.ModelRef.ProviderID()),
})
}
response := goapi.ListModelsResponse{
Object: "list",
Data: data,
}
serveJSON(w, r, m.logger, response)
}

View File

@ -0,0 +1,48 @@
package llmapi
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
sglog "github.com/sourcegraph/log"
"github.com/sourcegraph/sourcegraph/internal/openapi/goapi"
)
type modelsModelIDHandler struct {
logger sglog.Logger
GetModelConfig GetModelConfigurationFunc
}
var _ http.Handler = (*modelsModelIDHandler)(nil)
func (m *modelsModelIDHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
modelId := vars["modelId"]
if modelId == "" {
http.Error(w, "modelId is required", http.StatusBadRequest)
return
}
currentModelConfig, err := m.GetModelConfig()
if err != nil {
http.Error(w, fmt.Sprintf("modelConfigSvc.Get: %v", err), http.StatusInternalServerError)
return
}
for _, model := range currentModelConfig.Models {
if string(model.ModelRef) == modelId {
response := goapi.Model{
Object: "model",
Id: string(model.ModelRef),
OwnedBy: string(model.ModelRef.ProviderID()),
}
serveJSON(w, r, m.logger, response)
return
}
}
http.Error(w, "Model not found", http.StatusNotFound)
}

View File

@ -0,0 +1,78 @@
package llmapi
import (
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
types "github.com/sourcegraph/sourcegraph/internal/modelconfig/types"
"github.com/sourcegraph/sourcegraph/internal/openapi/goapi"
)
func TestModelsModelIDHandler(t *testing.T) {
mockModels := []types.Model{
{
ModelRef: "anthropic::unknown::claude-3-sonnet-20240229",
DisplayName: "Claude 3 Sonnet",
},
{
ModelRef: "openai::unknown::gpt-4",
DisplayName: "GPT-4",
},
}
c := newTest(t, func() (*types.ModelConfiguration, error) {
return &types.ModelConfiguration{Models: mockModels}, nil
})
testCases := []struct {
name string
modelID string
expectedStatus int
expectedModel *goapi.Model
}{
{
name: "Existing model",
modelID: "anthropic::unknown::claude-3-sonnet-20240229",
expectedStatus: http.StatusOK,
expectedModel: &goapi.Model{
Id: "anthropic::unknown::claude-3-sonnet-20240229",
Object: "model",
OwnedBy: "anthropic",
},
},
{
name: "Non-existent model",
modelID: "non-existent-model",
expectedStatus: http.StatusNotFound,
expectedModel: nil,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
req, err := http.NewRequest("GET", "/.api/llm/models/"+tc.modelID, nil)
require.NoError(t, err)
rr := httptest.NewRecorder()
c.Handler.ServeHTTP(rr, req)
assert.Equal(t, tc.expectedStatus, rr.Code)
if rr.Code == http.StatusOK {
assert.Equal(t, "application/json", rr.Header().Get("Content-Type"))
}
if tc.expectedModel != nil {
var response goapi.Model
err = json.Unmarshal(rr.Body.Bytes(), &response)
require.NoError(t, err)
assert.Equal(t, response, *tc.expectedModel)
}
})
}
}

View File

@ -0,0 +1,59 @@
package llmapi
import (
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/hexops/autogold/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
types "github.com/sourcegraph/sourcegraph/internal/modelconfig/types"
"github.com/sourcegraph/sourcegraph/internal/openapi/goapi"
)
func TestModelsHandler(t *testing.T) {
mockModels := []types.Model{
{
ModelRef: "anthropic::unknown::claude-3-sonnet-20240229",
DisplayName: "Claude 3 Sonnet",
},
{
ModelRef: "openai::unknown::gpt-4",
DisplayName: "GPT-4",
},
}
c := newTest(t, func() (*types.ModelConfiguration, error) {
return &types.ModelConfiguration{Models: mockModels}, nil
})
req, err := http.NewRequest("GET", "/.api/llm/models", nil)
require.NoError(t, err)
rr := httptest.NewRecorder()
c.Handler.ServeHTTP(rr, req)
assert.Equal(t, http.StatusOK, rr.Code)
assert.Equal(t, "application/json", rr.Header().Get("Content-Type"))
var response goapi.ListModelsResponse
err = json.Unmarshal(rr.Body.Bytes(), &response)
require.NoError(t, err)
autogold.Expect(goapi.ListModelsResponse{Object: "list", Data: []goapi.Model{
{
Id: "anthropic::unknown::claude-3-sonnet-20240229",
Object: "model",
OwnedBy: "anthropic",
},
{
Id: "openai::unknown::gpt-4",
Object: "model",
OwnedBy: "openai",
},
}}).Equal(t, response)
}

View File

@ -1,12 +1,19 @@
package llmapi
import (
"encoding/json"
"fmt"
"net/http"
"github.com/gorilla/mux"
"github.com/sourcegraph/log"
sglog "github.com/sourcegraph/log"
types "github.com/sourcegraph/sourcegraph/internal/modelconfig/types"
)
type GetModelConfigurationFunc func() (*types.ModelConfiguration, error)
func RegisterHandlers(m *mux.Router, apiHandler http.Handler, getModelConfigFunc GetModelConfigurationFunc) {
logger := sglog.Scoped("llmapi")
@ -15,4 +22,20 @@ func RegisterHandlers(m *mux.Router, apiHandler http.Handler, getModelConfigFunc
apiHandler: apiHandler,
GetModelConfig: getModelConfigFunc,
})
m.Path("/models").Methods("GET").Handler(&modelsHandler{
logger: logger,
GetModelConfig: getModelConfigFunc,
})
m.Path("/models/{modelId}").Methods("GET").Handler(&modelsModelIDHandler{
logger: logger,
GetModelConfig: getModelConfigFunc,
})
}
func serveJSON(w http.ResponseWriter, r *http.Request, logger sglog.Logger, v interface{}) {
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(v); err != nil {
logger.Error(fmt.Sprintf("writing %s JSON response body", r.URL.Path), log.Error(err))
http.Error(w, "writing response", http.StatusInternalServerError)
}
}

38
dev/generate-openapi-models.sh Executable file
View File

@ -0,0 +1,38 @@
#!/bin/sh
set -eu
# Script to generate Go models from TypeSpec, which defines REST APIs
# Ideally, this bash script should be replaced with a `bazel run` command
# but we keep it as a bash script for now to bootstrap our usage of TypeSpec.
# Check if openapi-generator is installed
if ! command -v openapi-generator > /dev/null 2>&1
then
echo "openapi-generator not found, installing from Homebrew..."
brew install openapi-generator
fi
# Check if main.tsp exists
MAIN_TSP="internal/openapi/main.tsp"
if [ ! -f "$MAIN_TSP" ]; then
echo "Error: $MAIN_TSP not found. The working directory must be at the root of the repo."
exit 1
fi
pnpm install
pnpm -C internal/openapi compile
mv internal/openapi/goapi internal/openapi/go
openapi-generator generate \
-g go \
-i internal/openapi/tsp-output/@typespec/openapi3/openapi.yaml \
-o internal/openapi \
-c internal/openapi/.openapi-generator/config.yml
mv internal/openapi/go internal/openapi/goapi
# Read the file content into a variable
content=$(cat internal/openapi/api/openapi.yaml)
# Prepend the comment and write back to the file
echo "# Code generated by OpenAPI Generator - DO NOT EDIT" > internal/openapi/api/openapi.yaml
echo "$content" >> internal/openapi/api/openapi.yaml
echo "internal/openapi/goapi"

9
internal/openapi/.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
# MacOS
.DS_Store
# Default TypeSpec output
tsp-output/
dist/
# Dependency directories
node_modules/

View File

@ -0,0 +1,17 @@
# OpenAPI Generator Ignore
# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.
go/logger.go
go/impl.go
go/helpers.go
go/api_default.go
go/api_default_service.go
go/api.go
go/error.go
go/routers.go
go/api_default_service.go
go.mod
main.go
Dockerfile
README.md

View File

@ -0,0 +1,4 @@
api/openapi.yaml
go/model_error.go
go/model_list_models_response.go
go/model_model.go

View File

@ -0,0 +1 @@
7.7.0

View File

@ -0,0 +1,4 @@
additionalProperties:
packageName: goapi
globalProperties:
models: true

View File

@ -0,0 +1,123 @@
# Code generated by OpenAPI Generator - DO NOT EDIT
openapi: 3.0.0
info:
title: Cody Service
version: 0.0.0
servers:
- url: /
paths:
/models:
get:
operationId: Models_list
parameters: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/ListModelsResponse'
description: The request has succeeded.
default:
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
description: An unexpected error response.
summary: "Lists the currently available models, and provides basic information\
\ about each one such as the owner and availability."
/models/{modelId}:
get:
operationId: Models_retrieveModel
parameters:
- explode: false
in: path
name: modelId
required: true
schema:
type: string
style: simple
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/Model'
description: The request has succeeded.
default:
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
description: An unexpected error response.
summary: "Retrieves a model instance, providing basic information about the\
\ model such as the owner and permissioning."
components:
schemas:
Error:
example:
code: 6
message: message
properties:
code:
format: int32
type: integer
message:
type: string
required:
- code
- message
type: object
ListModelsResponse:
example:
data:
- created: 0
owned_by: owned_by
id: id
object: model
- created: 0
owned_by: owned_by
id: id
object: model
object: list
properties:
object:
enum:
- list
type: string
data:
items:
$ref: '#/components/schemas/Model'
type: array
required:
- data
- object
type: object
Model:
description: Describes an OpenAI model offering that can be used with the API.
example:
created: 0
owned_by: owned_by
id: id
object: model
properties:
id:
description: 'The model identifier, which can be referenced in the API endpoints.'
type: string
object:
description: 'The object type, which is always "model".'
enum:
- model
type: string
created:
description: The Unix timestamp (in seconds) when the model was created.
format: int64
type: integer
owned_by:
description: The organization that owns the model.
type: string
required:
- created
- id
- object
- owned_by
type: object

47
internal/openapi/cody.tsp Normal file
View File

@ -0,0 +1,47 @@
import "@typespec/http";
import "@typespec/rest";
using TypeSpec.Http;
using TypeSpec.Rest;
@service({
title: "Cody Service",
})
namespace CodyService;
@route("/models")
interface Models {
@get
@summary("Lists the currently available models, and provides basic information about each one such as the owner and availability.")
list(): ListModelsResponse | Error;
@get
@summary("Retrieves a model instance, providing basic information about the model such as the owner and permissioning.")
retrieveModel(@path modelId: string): Model | Error;
}
@doc("Describes an OpenAI model offering that can be used with the API.")
model Model {
@doc("The model identifier, which can be referenced in the API endpoints.")
id: string;
@doc("The object type, which is always \"model\".")
object: "model";
@doc("The Unix timestamp (in seconds) when the model was created.")
created: int64;
@doc("The organization that owns the model.")
owned_by: string;
}
model ListModelsResponse {
object: "list";
data: Model[];
}
@error
model Error {
code: int32;
message: string;
}

View File

@ -0,0 +1,52 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
load("//dev:go_defs.bzl", "go_test")
go_library(
name = "go",
srcs = [
"error.go",
"helpers.go",
"model_chat_completions.go",
"model_error.go",
"model_list_models_response.go",
"model_model.go",
],
importpath = "github.com/sourcegraph/sourcegraph/internal/openapi/go",
visibility = ["//cmd/frontend:__subpackages__"],
deps = ["//lib/errors"],
)
go_test(
name = "go_test",
srcs = ["model_chat_completions_test.go"],
embed = [":go"],
deps = [
"@com_github_hexops_autogold_v2//:autogold",
"@com_github_stretchr_testify//assert",
],
)
go_library(
name = "goapi",
srcs = [
"error.go",
"helpers.go",
"model_chat_completions.go",
"model_error.go",
"model_list_models_response.go",
"model_model.go",
],
importpath = "github.com/sourcegraph/sourcegraph/internal/openapi/goapi",
visibility = ["//:__subpackages__"],
deps = ["//lib/errors"],
)
go_test(
name = "goapi_test",
srcs = ["model_chat_completions_test.go"],
embed = [":goapi"],
deps = [
"@com_github_hexops_autogold_v2//:autogold",
"@com_github_stretchr_testify//assert",
],
)

View File

@ -0,0 +1,14 @@
package goapi
import (
"fmt"
)
// RequiredError indicates that an error has occurred when parsing request parameters
type RequiredError struct {
Field string
}
func (e *RequiredError) Error() string {
return fmt.Sprintf("required field '%s' is zero value.", e.Field)
}

View File

@ -0,0 +1,10 @@
package goapi
import (
"reflect"
)
// IsZeroValue checks if the val is the zero-ed value.
func IsZeroValue(val interface{}) bool {
return val == nil || reflect.DeepEqual(val, reflect.Zero(reflect.TypeOf(val)).Interface())
}

View File

@ -1,4 +1,4 @@
package llmapi
package goapi
import (
"encoding/json"

View File

@ -1,4 +1,4 @@
package llmapi
package goapi
import (
"encoding/json"

View File

@ -0,0 +1,37 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
/*
* Cody Service
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 0.0.0
*/
package goapi
type Error struct {
Code int32 `json:"code"`
Message string `json:"message"`
}
// AssertErrorRequired checks if the required fields are not zero-ed
func AssertErrorRequired(obj Error) error {
elements := map[string]interface{}{
"code": obj.Code,
"message": obj.Message,
}
for name, el := range elements {
if isZero := IsZeroValue(el); isZero {
return &RequiredError{Field: name}
}
}
return nil
}
// AssertErrorConstraints checks if the values respects the defined constraints
func AssertErrorConstraints(obj Error) error {
return nil
}

View File

@ -0,0 +1,47 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
/*
* Cody Service
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 0.0.0
*/
package goapi
type ListModelsResponse struct {
Object string `json:"object"`
Data []Model `json:"data"`
}
// AssertListModelsResponseRequired checks if the required fields are not zero-ed
func AssertListModelsResponseRequired(obj ListModelsResponse) error {
elements := map[string]interface{}{
"object": obj.Object,
"data": obj.Data,
}
for name, el := range elements {
if isZero := IsZeroValue(el); isZero {
return &RequiredError{Field: name}
}
}
for _, el := range obj.Data {
if err := AssertModelRequired(el); err != nil {
return err
}
}
return nil
}
// AssertListModelsResponseConstraints checks if the values respects the defined constraints
func AssertListModelsResponseConstraints(obj ListModelsResponse) error {
for _, el := range obj.Data {
if err := AssertModelConstraints(el); err != nil {
return err
}
}
return nil
}

View File

@ -0,0 +1,49 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
/*
* Cody Service
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 0.0.0
*/
package goapi
// Model - Describes an OpenAI model offering that can be used with the API.
type Model struct {
// The model identifier, which can be referenced in the API endpoints.
Id string `json:"id"`
// The object type, which is always \"model\".
Object string `json:"object"`
// The Unix timestamp (in seconds) when the model was created.
Created int64 `json:"created"`
// The organization that owns the model.
OwnedBy string `json:"owned_by"`
}
// AssertModelRequired checks if the required fields are not zero-ed
func AssertModelRequired(obj Model) error {
elements := map[string]interface{}{
"id": obj.Id,
"object": obj.Object,
"created": obj.Created,
"owned_by": obj.OwnedBy,
}
for name, el := range elements {
if isZero := IsZeroValue(el); isZero {
return &RequiredError{Field: name}
}
}
return nil
}
// AssertModelConstraints checks if the values respects the defined constraints
func AssertModelConstraints(obj Model) error {
return nil
}

View File

@ -0,0 +1 @@
import "./cody.tsp";

View File

@ -0,0 +1,21 @@
{
"name": "sourcegraph-rest-api",
"version": "0.1.0",
"type": "module",
"scripts": {
"compile": "tsp compile ."
},
"peerDependencies": {
"@typespec/compiler": "0.59.0",
"@typespec/http": "0.59.0",
"@typespec/rest": "0.59.0",
"@typespec/openapi3": "0.59.0"
},
"devDependencies": {
"@typespec/compiler": "0.59.0",
"@typespec/http": "0.59.0",
"@typespec/rest": "0.59.0",
"@typespec/openapi3": "0.59.0"
},
"private": true
}

View File

@ -0,0 +1,2 @@
emit:
- "@typespec/openapi3"

View File

@ -1785,6 +1785,21 @@ importers:
specifier: ^9.12.4
version: 9.12.4
internal/openapi:
devDependencies:
'@typespec/compiler':
specifier: 0.59.0
version: 0.59.0
'@typespec/http':
specifier: 0.59.0
version: 0.59.0(@typespec/compiler@0.59.0)
'@typespec/openapi3':
specifier: 0.59.0
version: 0.59.0(@typespec/compiler@0.59.0)(@typespec/http@0.59.0)(@typespec/openapi@0.59.0)(@typespec/versioning@0.59.0)(openapi-types@12.1.3)
'@typespec/rest':
specifier: 0.59.0
version: 0.59.0(@typespec/compiler@0.59.0)(@typespec/http@0.59.0)
internal/appliance/frontend/maintenance:
dependencies:
'@emotion/react':
@ -1901,6 +1916,10 @@ packages:
js-yaml: 3.14.1
dev: true
/@apidevtools/swagger-methods@3.0.2:
resolution: {integrity: sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==}
dev: true
/@apollo/client@3.8.0-alpha.7(graphql-ws@5.15.0)(graphql@15.4.0)(react-dom@18.1.0)(react@18.1.0):
resolution: {integrity: sha512-pwyACANhC4R0VnEXn4Uv7DEIOr3V6kmKC+Eh3wlspuhP7RLHsU31oFYXmNs2THHAMDdXAK96axutd6qP86eZ+Q==}
peerDependencies:
@ -2018,7 +2037,7 @@ packages:
resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/highlight': 7.23.4
'@babel/highlight': 7.24.7
chalk: 2.4.2
/@babel/code-frame@7.24.7:
@ -2026,7 +2045,7 @@ packages:
engines: {node: '>=6.9.0'}
dependencies:
'@babel/highlight': 7.24.7
picocolors: 1.0.0
picocolors: 1.0.1
/@babel/compat-data@7.24.1:
resolution: {integrity: sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==}
@ -2063,7 +2082,7 @@ packages:
engines: {node: '>=6.9.0'}
dependencies:
'@ampproject/remapping': 2.3.0
'@babel/code-frame': 7.23.5
'@babel/code-frame': 7.24.7
'@babel/generator': 7.23.6
'@babel/helper-compilation-targets': 7.23.6
'@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0)
@ -2274,7 +2293,7 @@ packages:
'@babel/helper-module-imports': 7.24.7
'@babel/helper-simple-access': 7.22.5
'@babel/helper-split-export-declaration': 7.22.6
'@babel/helper-validator-identifier': 7.22.20
'@babel/helper-validator-identifier': 7.24.7
dev: true
/@babel/helper-module-transforms@7.24.7(@babel/core@7.18.5):
@ -2418,14 +2437,6 @@ packages:
'@babel/template': 7.24.7
'@babel/types': 7.24.7
/@babel/highlight@7.23.4:
resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/helper-validator-identifier': 7.24.7
chalk: 2.4.2
js-tokens: 4.0.0
/@babel/highlight@7.24.7:
resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==}
engines: {node: '>=6.9.0'}
@ -2433,7 +2444,7 @@ packages:
'@babel/helper-validator-identifier': 7.24.7
chalk: 2.4.2
js-tokens: 4.0.0
picocolors: 1.0.0
picocolors: 1.0.1
/@babel/parser@7.10.5:
resolution: {integrity: sha512-wfryxy4bE1UivvQKSQDU4/X6dr+i8bctjUjj8Zyt3DQy7NtPizJXT8M52nqpNKL+nq2PW8lxk4ZqLj0fD4B4hQ==}
@ -3505,7 +3516,7 @@ packages:
resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/code-frame': 7.23.5
'@babel/code-frame': 7.24.7
'@babel/parser': 7.24.0
'@babel/types': 7.24.0
dev: true
@ -3536,7 +3547,7 @@ packages:
resolution: {integrity: sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/code-frame': 7.23.5
'@babel/code-frame': 7.24.7
'@babel/generator': 7.23.6
'@babel/helper-environment-visitor': 7.22.20
'@babel/helper-function-name': 7.23.0
@ -5895,6 +5906,11 @@ packages:
resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
engines: {node: '>=12.22'}
/@humanwhocodes/momoa@2.0.4:
resolution: {integrity: sha512-RE815I4arJFtt+FVeU1Tgp9/Xvecacji8w/V6XtXsWWH/wz/eNkNbhb+ny/+PlVZjV0rxQpRSQKNKE3lcktHEA==}
engines: {node: '>=10.10.0'}
dev: true
/@humanwhocodes/object-schema@1.2.1:
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
deprecated: Use @eslint/object-schema instead
@ -7134,7 +7150,7 @@ packages:
'@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
'@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
'@opentelemetry/semantic-conventions': 1.24.1
semver: 7.6.0
semver: 7.6.3
dev: false
/@opentelemetry/instrumentation-ioredis@0.40.0(@opentelemetry/api@1.8.0):
@ -7259,7 +7275,7 @@ packages:
'@types/shimmer': 1.0.5
import-in-the-middle: 1.4.2
require-in-the-middle: 7.3.0
semver: 7.6.0
semver: 7.6.3
shimmer: 1.2.1
dev: false
optional: true
@ -7275,7 +7291,7 @@ packages:
'@types/shimmer': 1.0.5
import-in-the-middle: 1.7.4
require-in-the-middle: 7.3.0
semver: 7.6.0
semver: 7.6.3
shimmer: 1.2.1
dev: false
@ -8428,10 +8444,10 @@ packages:
hermes-profile-transformer: 0.0.6
node-stream-zip: 1.15.0
ora: 5.4.1
semver: 7.6.0
semver: 7.6.3
strip-ansi: 5.2.0
wcwidth: 1.0.1
yaml: 2.4.1
yaml: 2.4.5
transitivePeerDependencies:
- encoding
dev: false
@ -8505,7 +8521,7 @@ packages:
node-fetch: 2.7.0
open: 6.4.0
ora: 5.4.1
semver: 7.6.0
semver: 7.6.3
shell-quote: 1.8.1
sudo-prompt: 9.2.1
transitivePeerDependencies:
@ -8540,7 +8556,7 @@ packages:
fs-extra: 8.1.0
graceful-fs: 4.2.11
prompts: 2.4.2
semver: 7.6.0
semver: 7.6.3
transitivePeerDependencies:
- bufferutil
- encoding
@ -8877,6 +8893,53 @@ packages:
zustand: 3.7.2(react@18.1.0)
dev: false
/@readme/better-ajv-errors@1.6.0(ajv@8.17.1):
resolution: {integrity: sha512-9gO9rld84Jgu13kcbKRU+WHseNhaVt76wYMeRDGsUGYxwJtI3RmEJ9LY9dZCYQGI8eUZLuxb5qDja0nqklpFjQ==}
engines: {node: '>=14'}
peerDependencies:
ajv: 4.11.8 - 8
dependencies:
'@babel/code-frame': 7.24.7
'@babel/runtime': 7.24.0
'@humanwhocodes/momoa': 2.0.4
ajv: 8.17.1
chalk: 4.1.2
json-to-ast: 2.1.0
jsonpointer: 5.0.1
leven: 3.1.0
dev: true
/@readme/json-schema-ref-parser@1.2.0:
resolution: {integrity: sha512-Bt3QVovFSua4QmHa65EHUmh2xS0XJ3rgTEUPH998f4OW4VVJke3BuS16f+kM0ZLOGdvIrzrPRqwihuv5BAjtrA==}
dependencies:
'@jsdevtools/ono': 7.1.3
'@types/json-schema': 7.0.15
call-me-maybe: 1.0.1
js-yaml: 4.1.0
dev: true
/@readme/openapi-parser@2.6.0(openapi-types@12.1.3):
resolution: {integrity: sha512-pyFJXezWj9WI1O+gdp95CoxfY+i+Uq3kKk4zXIFuRAZi9YnHpHOpjumWWr67wkmRTw19Hskh9spyY0Iyikf3fA==}
engines: {node: '>=18'}
peerDependencies:
openapi-types: '>=7'
dependencies:
'@apidevtools/swagger-methods': 3.0.2
'@jsdevtools/ono': 7.1.3
'@readme/better-ajv-errors': 1.6.0(ajv@8.17.1)
'@readme/json-schema-ref-parser': 1.2.0
'@readme/openapi-schemas': 3.1.0
ajv: 8.17.1
ajv-draft-04: 1.0.0(ajv@8.17.1)
call-me-maybe: 1.0.1
openapi-types: 12.1.3
dev: true
/@readme/openapi-schemas@3.1.0:
resolution: {integrity: sha512-9FC/6ho8uFa8fV50+FPy/ngWN53jaUu4GRXlAjcxIRrzhltJnpKkBG2Tp0IDraFJeWrOpk84RJ9EMEEYzaI1Bw==}
engines: {node: '>=18'}
dev: true
/@remix-run/router@1.17.1:
resolution: {integrity: sha512-mCOMec4BKd6BRGBZeSnGiIgwsbLGp3yhVqAD8H+PxiRNEHgDpZb8J1TnrSDlg97t0ySKMQJTHCWBCmBpSmkF6Q==}
engines: {node: '>=14.0.0'}
@ -9601,6 +9664,11 @@ packages:
engines: {node: '>=10'}
dev: false
/@sindresorhus/merge-streams@2.3.0:
resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==}
engines: {node: '>=18'}
dev: true
/@sinonjs/commons@1.8.3:
resolution: {integrity: sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==}
dependencies:
@ -10634,10 +10702,10 @@ packages:
jscodeshift: 0.15.2(@babel/preset-env@7.24.3)
leven: 3.1.0
ora: 5.4.1
prettier: 3.2.5
prettier: 3.3.3
prompts: 2.4.2
read-pkg-up: 7.0.1
semver: 7.6.0
semver: 7.6.3
strip-json-comments: 3.1.1
tempy: 1.0.1
tiny-invariant: 1.3.3
@ -10710,7 +10778,7 @@ packages:
globby: 11.1.0
jscodeshift: 0.15.2(@babel/preset-env@7.24.3)
lodash: 4.17.21
prettier: 3.2.5
prettier: 3.3.3
recast: 0.23.6
tiny-invariant: 1.3.3
dev: true
@ -10875,7 +10943,7 @@ packages:
pkg-dir: 5.0.0
pretty-hrtime: 1.0.3
resolve-from: 5.0.0
semver: 7.6.0
semver: 7.6.3
tempy: 1.0.1
tiny-invariant: 1.3.3
ts-dedent: 2.2.0
@ -10938,7 +11006,7 @@ packages:
pretty-hrtime: 1.0.3
prompts: 2.4.2
read-pkg-up: 7.0.1
semver: 7.6.0
semver: 7.6.3
telejson: 7.2.0
tiny-invariant: 1.3.3
ts-dedent: 2.2.0
@ -10990,7 +11058,7 @@ packages:
pretty-hrtime: 1.0.3
prompts: 2.4.2
read-pkg-up: 7.0.1
semver: 7.6.0
semver: 7.6.3
telejson: 7.2.0
tiny-invariant: 1.3.3
ts-dedent: 2.2.0
@ -11164,7 +11232,7 @@ packages:
memoizerific: 1.11.3
react: 18.1.0
react-dom: 18.1.0(react@18.1.0)
semver: 7.6.0
semver: 7.6.3
store2: 2.14.3
telejson: 7.2.0
ts-dedent: 2.2.0
@ -11776,7 +11844,7 @@ packages:
resolution: {integrity: sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==}
engines: {node: '>=14'}
dependencies:
'@babel/code-frame': 7.23.5
'@babel/code-frame': 7.24.7
'@babel/runtime': 7.24.0
'@types/aria-query': 5.0.4
aria-query: 5.1.3
@ -12830,7 +12898,7 @@ packages:
graphemer: 1.4.0
ignore: 5.3.1
natural-compare: 1.4.0
semver: 7.6.0
semver: 7.6.3
ts-api-utils: 1.0.3(typescript@5.4.2)
typescript: 5.4.2
dev: true
@ -12960,7 +13028,7 @@ packages:
debug: 4.3.4
globby: 11.1.0
is-glob: 4.0.3
semver: 7.6.0
semver: 7.6.3
tsutils: 3.21.0(typescript@5.4.2)
typescript: 5.4.2
dev: true
@ -12979,7 +13047,7 @@ packages:
debug: 4.3.4
globby: 11.1.0
is-glob: 4.0.3
semver: 7.6.0
semver: 7.6.3
tsutils: 3.21.0(typescript@5.4.2)
typescript: 5.4.2
dev: true
@ -12999,7 +13067,7 @@ packages:
globby: 11.1.0
is-glob: 4.0.3
minimatch: 9.0.3
semver: 7.6.0
semver: 7.6.3
ts-api-utils: 1.0.3(typescript@5.4.2)
typescript: 5.4.2
dev: true
@ -13018,7 +13086,7 @@ packages:
'@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.2)
eslint: 8.57.0
eslint-scope: 5.1.1
semver: 7.6.0
semver: 7.6.3
transitivePeerDependencies:
- typescript
dev: true
@ -13036,7 +13104,7 @@ packages:
'@typescript-eslint/types': 6.21.0
'@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.2)
eslint: 8.57.0
semver: 7.6.0
semver: 7.6.3
transitivePeerDependencies:
- typescript
dev: true
@ -13065,6 +13133,87 @@ packages:
eslint-visitor-keys: 3.4.3
dev: true
/@typespec/compiler@0.59.0:
resolution: {integrity: sha512-fqh2TeAWQyt70f7NkfwOvoQMqHAfGzIfvcUi+XW55+ms6opiqNXBIT822Jr+T4fNo1PgsnbKC34n6SSIMxnOqw==}
engines: {node: '>=18.0.0'}
hasBin: true
dependencies:
'@babel/code-frame': 7.24.7
ajv: 8.17.1
change-case: 5.4.4
globby: 14.0.2
mustache: 4.2.0
picocolors: 1.0.1
prettier: 3.3.3
prompts: 2.4.2
semver: 7.6.3
temporal-polyfill: 0.2.5
vscode-languageserver: 9.0.1
vscode-languageserver-textdocument: 1.0.12
yaml: 2.4.5
yargs: 17.7.2
dev: true
/@typespec/http@0.59.0(@typespec/compiler@0.59.0):
resolution: {integrity: sha512-P8kJBHmkqYHhojO97Tnj8FH+UInWzGBl2I9Z6ZX6sVUVW9/87hoovgCcVmvU1xMUD/xvKzX3m70fbRXhkocsGQ==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@typespec/compiler': ~0.59.0
dependencies:
'@typespec/compiler': 0.59.0
dev: true
/@typespec/openapi3@0.59.0(@typespec/compiler@0.59.0)(@typespec/http@0.59.0)(@typespec/openapi@0.59.0)(@typespec/versioning@0.59.0)(openapi-types@12.1.3):
resolution: {integrity: sha512-xwdWPPRtjsLxXjsebNppaHrFPF6rJiWkAEHCsK0elwvaPSruZvYfPhXpx1HnNkC2glb0NHgmxvXg7EmMwIYYcA==}
engines: {node: '>=18.0.0'}
hasBin: true
peerDependencies:
'@typespec/compiler': ~0.59.0
'@typespec/http': ~0.59.0
'@typespec/openapi': ~0.59.0
'@typespec/versioning': ~0.59.0
dependencies:
'@readme/openapi-parser': 2.6.0(openapi-types@12.1.3)
'@typespec/compiler': 0.59.0
'@typespec/http': 0.59.0(@typespec/compiler@0.59.0)
'@typespec/openapi': 0.59.0(@typespec/compiler@0.59.0)(@typespec/http@0.59.0)
'@typespec/versioning': 0.59.0(@typespec/compiler@0.59.0)
yaml: 2.4.5
transitivePeerDependencies:
- openapi-types
dev: true
/@typespec/openapi@0.59.0(@typespec/compiler@0.59.0)(@typespec/http@0.59.0):
resolution: {integrity: sha512-do1Dm5w0MuK3994gYTBg6qMfgeIxmmsDqnz3zimYKMPpbnUBi4F6/o4iCfn0Fn9kaNl+H6UlOzZpsZW9xHui1Q==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@typespec/compiler': ~0.59.0
'@typespec/http': ~0.59.0
dependencies:
'@typespec/compiler': 0.59.0
'@typespec/http': 0.59.0(@typespec/compiler@0.59.0)
dev: true
/@typespec/rest@0.59.0(@typespec/compiler@0.59.0)(@typespec/http@0.59.0):
resolution: {integrity: sha512-wGrmjRDUMgMn9fqusRhu36hC2GOvirz5O01VSrmAEOH6k1L2GX0Mq70gOdZa4kkkWyHYDKb7GdjfaLe8v+OH6w==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@typespec/compiler': ~0.59.0
'@typespec/http': ~0.59.0
dependencies:
'@typespec/compiler': 0.59.0
'@typespec/http': 0.59.0(@typespec/compiler@0.59.0)
dev: true
/@typespec/versioning@0.59.0(@typespec/compiler@0.59.0):
resolution: {integrity: sha512-aihO/ux0lLmsuYAdGVkiBflSudcZokYG42SELk1FtMFo609G3Pd7ep7hau6unBnMIceQZejB0ow5UGRupK4X5A==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@typespec/compiler': ~0.59.0
dependencies:
'@typespec/compiler': 0.59.0
dev: true
/@ungap/promise-all-settled@1.1.2:
resolution: {integrity: sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==}
dev: true
@ -13827,6 +13976,17 @@ packages:
indent-string: 4.0.0
dev: true
/ajv-draft-04@1.0.0(ajv@8.17.1):
resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==}
peerDependencies:
ajv: ^8.5.0
peerDependenciesMeta:
ajv:
optional: true
dependencies:
ajv: 8.17.1
dev: true
/ajv-formats@2.1.1(ajv@8.11.2):
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
peerDependencies:
@ -13861,6 +14021,16 @@ packages:
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
uri-js: 4.4.1
dev: false
/ajv@8.17.1:
resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
dependencies:
fast-deep-equal: 3.1.3
fast-uri: 3.0.1
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
dev: true
/anser@1.4.10:
resolution: {integrity: sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==}
@ -14878,6 +15048,10 @@ packages:
tslib: 2.1.0
dev: true
/change-case@5.4.4:
resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==}
dev: true
/character-entities-legacy@1.1.2:
resolution: {integrity: sha512-9NB2VbXtXYWdXzqrvAHykE/f0QJxzaKIpZ5QzNZrrgQ7Iyxr2vnfS8fCBNVW9nUEZE0lo57nxKRqnzY/dKrwlA==}
dev: true
@ -15195,6 +15369,11 @@ packages:
engines: {node: '>=6'}
dev: false
/code-error-fragment@0.0.230:
resolution: {integrity: sha512-cadkfKp6932H8UkhzE/gcUqhRMNf8jHzkAN7+5Myabswaghu4xABTgPHDCjW+dBAJxj/SpkTYokpzDqY4pCzQw==}
engines: {node: '>= 4'}
dev: true
/code-point-at@1.1.0:
resolution: {integrity: sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==}
engines: {node: '>=0.10.0'}
@ -17295,7 +17474,7 @@ packages:
eslint: 8.57.0
esquery: 1.5.0
is-builtin-module: 3.2.1
semver: 7.6.0
semver: 7.6.3
spdx-expression-parse: 3.0.1
dev: true
@ -17435,7 +17614,7 @@ packages:
peerDependencies:
eslint: '>=8.44.0'
dependencies:
'@babel/helper-validator-identifier': 7.22.20
'@babel/helper-validator-identifier': 7.24.7
'@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
ci-info: 3.9.0
clean-regexp: 1.0.0
@ -17449,7 +17628,7 @@ packages:
read-pkg-up: 7.0.1
regexp-tree: 0.1.27
regjsparser: 0.10.0
semver: 7.6.0
semver: 7.6.3
strip-indent: 3.0.0
dev: true
@ -17554,7 +17733,7 @@ packages:
optionator: 0.9.3
progress: 2.0.3
regexpp: 3.2.0
semver: 7.6.0
semver: 7.6.3
strip-ansi: 6.0.1
strip-json-comments: 3.1.1
text-table: 0.2.0
@ -17924,6 +18103,10 @@ packages:
resolution: {integrity: sha512-R9bHCvweUxxwkDwhjav5vxpFvdPGlVngtqmx4pIZfSUhM/Q4NiIUHB456BAf+Q1Nwu3HEZYONtu+Rya+af4jiQ==}
dev: true
/fast-uri@3.0.1:
resolution: {integrity: sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==}
dev: true
/fast-url-parser@1.1.3:
resolution: {integrity: sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==}
dependencies:
@ -18666,6 +18849,18 @@ packages:
merge2: 1.4.1
slash: 4.0.0
/globby@14.0.2:
resolution: {integrity: sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==}
engines: {node: '>=18'}
dependencies:
'@sindresorhus/merge-streams': 2.3.0
fast-glob: 3.3.2
ignore: 5.3.1
path-type: 5.0.0
slash: 5.1.0
unicorn-magic: 0.1.0
dev: true
/globby@7.1.1:
resolution: {integrity: sha512-yANWAN2DUcBtuus5Cpd+SKROzXHs2iVXFZt/Ykrfz6SAXqacLX25NZpltE+39ceMexYF4TtEadjuSTw8+3wX4g==}
engines: {node: '>=4'}
@ -18808,6 +19003,10 @@ packages:
/graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
/grapheme-splitter@1.0.4:
resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==}
dev: true
/graphemer@1.4.0:
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
@ -18900,7 +19099,7 @@ packages:
dependencies:
graphql: 15.4.0
nullthrows: 1.1.1
vscode-languageserver-types: 3.17.2
vscode-languageserver-types: 3.17.5
dev: false
/graphql-request@5.0.0(graphql@15.4.0):
@ -20207,7 +20406,7 @@ packages:
resolution: {integrity: sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==}
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
dependencies:
'@babel/code-frame': 7.23.5
'@babel/code-frame': 7.24.7
'@jest/types': 27.5.1
'@types/stack-utils': 2.0.3
chalk: 4.1.2
@ -20542,6 +20741,14 @@ packages:
resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==}
dev: true
/json-to-ast@2.1.0:
resolution: {integrity: sha512-W9Lq347r8tA1DfMvAGn9QNcgYm4Wm7Yc+k8e6vezpMnRT+NHbtlxgNBXRVjXe9YM6eTn6+p/MKOlV/aABJcSnQ==}
engines: {node: '>= 4'}
dependencies:
code-error-fragment: 0.0.230
grapheme-splitter: 1.0.4
dev: true
/json-to-pretty-yaml@1.2.2:
resolution: {integrity: sha512-rvm6hunfCcqegwYaG5T4yKJWxc9FXFgBVrcTZ4XfSVRwa5HA/Xs+vB/Eo9treYYHCeNM0nrSUr82V/M31Urc7A==}
engines: {node: '>= 0.2.0'}
@ -20581,6 +20788,11 @@ packages:
resolution: {integrity: sha512-trvBk1ki43VZptdBI5rIlG4YOzyeH/WefQt5rj1grasPn4iiZWKet8nkgc4GlsAylaztn0qZfUYOiTsASJFdNA==}
dev: true
/jsonpointer@5.0.1:
resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==}
engines: {node: '>=0.10.0'}
dev: true
/jsonwebtoken@8.5.1:
resolution: {integrity: sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==}
engines: {node: '>=4', npm: '>=1.4.28'}
@ -22252,6 +22464,11 @@ packages:
- encoding
dev: true
/mustache@4.2.0:
resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==}
hasBin: true
dev: true
/mute-stream@0.0.8:
resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==}
dev: true
@ -22345,7 +22562,7 @@ packages:
engines: {node: '>=10'}
requiresBuild: true
dependencies:
semver: 7.6.0
semver: 7.6.3
dev: true
/node-abort-controller@3.1.1:
@ -22462,7 +22679,7 @@ packages:
dependencies:
hosted-git-info: 3.0.8
resolve: 1.22.8
semver: 7.6.0
semver: 7.6.3
validate-npm-package-license: 3.0.4
dev: true
@ -22711,6 +22928,10 @@ packages:
is-wsl: 2.2.0
dev: true
/openapi-types@12.1.3:
resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==}
dev: true
/opentelemetry-instrumentation-fetch-node@1.2.0:
resolution: {integrity: sha512-aiSt/4ubOTyb1N5C2ZbGrBvaJOXIZhZvpRPYuUVxQJe27wJZqf/o65iPrqgLcgfeOLaQ8cS2Q+762jrYvniTrA==}
engines: {node: '>18.0.0'}
@ -23184,6 +23405,11 @@ packages:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
/path-type@5.0.0:
resolution: {integrity: sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==}
engines: {node: '>=12'}
dev: true
/path@0.12.7:
resolution: {integrity: sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==}
dependencies:
@ -23257,6 +23483,9 @@ packages:
/picocolors@1.0.0:
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
/picocolors@1.0.1:
resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
/picomatch@2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
@ -23670,8 +23899,8 @@ packages:
hasBin: true
dev: true
/prettier@3.2.5:
resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==}
/prettier@3.3.3:
resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==}
engines: {node: '>=14'}
hasBin: true
dev: true
@ -25349,6 +25578,11 @@ packages:
dependencies:
lru-cache: 6.0.0
/semver@7.6.3:
resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==}
engines: {node: '>=10'}
hasBin: true
/send@0.18.0:
resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
engines: {node: '>= 0.8.0'}
@ -25554,7 +25788,7 @@ packages:
resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==}
engines: {node: '>=10'}
dependencies:
semver: 7.6.0
semver: 7.6.3
dev: true
/sinon@10.0.0:
@ -25619,6 +25853,11 @@ packages:
resolution: {integrity: sha512-n6KkmvKS0623igEVj3FF0OZs1gYYJ0o0Hj939yc1fyxl2xt+xYpLnzJB6xBSqOfV9ZFLEWodBBN/heZJahuIJQ==}
engines: {node: '>=14.16'}
/slash@5.1.0:
resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==}
engines: {node: '>=14.16'}
dev: true
/slice-ansi@2.1.0:
resolution: {integrity: sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==}
engines: {node: '>=6'}
@ -26363,7 +26602,7 @@ packages:
mime: 2.6.0
qs: 6.12.0
readable-stream: 3.6.2
semver: 7.6.0
semver: 7.6.3
dev: true
/supports-color@2.0.0:
@ -26570,7 +26809,7 @@ packages:
resolution: {integrity: sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==}
engines: {node: '>=10.0.0'}
dependencies:
ajv: 8.11.2
ajv: 8.17.1
lodash.truncate: 4.4.2
slice-ansi: 4.0.0
string-width: 4.2.3
@ -26635,6 +26874,16 @@ packages:
dependencies:
rimraf: 2.6.3
/temporal-polyfill@0.2.5:
resolution: {integrity: sha512-ye47xp8Cb0nDguAhrrDS1JT1SzwEV9e26sSsrWzVu+yPZ7LzceEcH0i2gci9jWfOfSCCgM3Qv5nOYShVUUFUXA==}
dependencies:
temporal-spec: 0.2.4
dev: true
/temporal-spec@0.2.4:
resolution: {integrity: sha512-lDMFv4nKQrSjlkHKAlHVqKrBG4DyFfa9F74cmBZ3Iy3ed8yvWnlWSIdi4IKfSqwmazAohBNwiN64qGx4y5Q3IQ==}
dev: true
/tempy@1.0.1:
resolution: {integrity: sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==}
engines: {node: '>=10'}
@ -27289,6 +27538,11 @@ packages:
resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==}
engines: {node: '>=4'}
/unicorn-magic@0.1.0:
resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==}
engines: {node: '>=18'}
dev: true
/unimport@3.7.1:
resolution: {integrity: sha512-V9HpXYfsZye5bPPYUgs0Otn3ODS1mDUciaBlXljI4C2fTwfFpvFZRywmlOu943puN9sncxROMZhsZCjNXEpzEQ==}
dependencies:
@ -27492,7 +27746,7 @@ packages:
dependencies:
browserslist: 4.23.0
escalade: 3.1.1
picocolors: 1.0.0
picocolors: 1.0.1
/upper-case-first@2.0.2:
resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==}
@ -27756,7 +28010,7 @@ packages:
cac: 6.7.14
debug: 4.3.4
pathe: 1.1.2
picocolors: 1.0.0
picocolors: 1.0.1
vite: 5.1.5(@types/node@20.8.0)(sass@1.32.4)
transitivePeerDependencies:
- '@types/node'
@ -28125,6 +28379,22 @@ packages:
yazl: 2.5.1
dev: true
/vscode-jsonrpc@8.2.0:
resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==}
engines: {node: '>=14.0.0'}
dev: true
/vscode-languageserver-protocol@3.17.5:
resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==}
dependencies:
vscode-jsonrpc: 8.2.0
vscode-languageserver-types: 3.17.5
dev: true
/vscode-languageserver-textdocument@1.0.12:
resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==}
dev: true
/vscode-languageserver-textdocument@1.0.2:
resolution: {integrity: sha512-T7uPC18+f8mYE4lbVZwb3OSmvwTZm3cuFhrdx9Bn2l11lmp3SvSuSVjy2JtvrghzjAo4G6Trqny2m9XGnFnWVA==}
dev: false
@ -28133,6 +28403,16 @@ packages:
resolution: {integrity: sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA==}
dev: false
/vscode-languageserver-types@3.17.5:
resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==}
/vscode-languageserver@9.0.1:
resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==}
hasBin: true
dependencies:
vscode-languageserver-protocol: 3.17.5
dev: true
/vscode-uri@3.0.7:
resolution: {integrity: sha512-eOpPHogvorZRobNqJGhapa0JdwaxpjVvyBp0QIUMRMSf8ZAlqOdEquKuRmw9Qwu0qXtJIWqFtMkmvJjUZmMjVA==}
dev: false
@ -28682,6 +28962,11 @@ packages:
engines: {node: '>= 14'}
hasBin: true
/yaml@2.4.5:
resolution: {integrity: sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==}
engines: {node: '>= 14'}
hasBin: true
/yargs-parser@13.1.2:
resolution: {integrity: sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==}
dependencies:

View File

@ -4,3 +4,4 @@ packages:
- '!client/cody-context-filters-test-dataset'
- 'schema'
- 'internal/appliance/frontend/maintenance'
- 'internal/openapi'