sourcegraph/dev/generate-openapi-models.sh
Ólafur Páll Geirsson 1b1229c867
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

39 lines
1.3 KiB
Bash
Executable File

#!/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"