sourcegraph/dev/generate-openapi-models.sh

39 lines
1.3 KiB
Bash
Raw Permalink Normal View History

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 -->
2024-08-14 10:47:00 +00:00
#!/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"