diff --git a/.github/workflows/release-go.yml b/.github/workflows/release-go.yml new file mode 100644 index 0000000000..08ef2889f9 --- /dev/null +++ b/.github/workflows/release-go.yml @@ -0,0 +1,116 @@ +name: Release gRPC goLang packages + +on: + push: + branches: [main] + paths: + - 'crates/grpc_client/go/**' + - 'crates/grpc_client/proto/**' + pull_request: + branches: [main] + paths: + - 'crates/grpc_client/go/**' + - 'crates/grpc_client/proto/**' + workflow_dispatch: + +permissions: + contents: write + +jobs: + test: + name: Test Go Client + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.25' + + - name: Install protoc + uses: arduino/setup-protoc@v3 + with: + repo-token: ${{ github.token }} + + - name: Install protoc-gen-go + run: | + go install google.golang.org/protobuf/cmd/protoc-gen-go@latest + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest + + - name: Generate Code + run: bash crates/grpc_client/go/generate.sh + + # Generated files are ignored, so we don't need to verify clean git tree here. + + - name: Test + run: cd crates/grpc_client/go && go test ./... + + release: + name: Tag Release + needs: test + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.25' + + - name: Install protoc + uses: arduino/setup-protoc@v3 + with: + repo-token: ${{ github.token }} + + - name: Install protoc-gen-go + run: | + go install google.golang.org/protobuf/cmd/protoc-gen-go@latest + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest + + - name: Generate Code + run: bash crates/grpc_client/go/generate.sh + + - name: Commit Generated Code + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add -f crates/grpc_client/go/generated + if [ -d "crates/grpc_client/go/proto" ]; then + git add -f crates/grpc_client/go/proto + fi + if ! git diff --cached --quiet; then + git commit -m "chore: include generated code for release [skip ci]" + fi + + - name: Read Version + id: version + run: | + if [ ! -f crates/grpc_client/go/VERSION ]; then + echo "Error: VERSION file missing" + exit 1 + fi + VERSION=$(cat crates/grpc_client/go/VERSION | tr -d '[:space:]') + echo "version=$VERSION" >> $GITHUB_OUTPUT + + - name: Check if tag exists + id: check_tag + run: | + TAG="crates/grpc_client/go/v${{ steps.version.outputs.version }}" + if git rev-parse "$TAG" >/dev/null 2>&1; then + echo "exists=true" >> $GITHUB_OUTPUT + else + echo "exists=false" >> $GITHUB_OUTPUT + fi + + - name: Create and Push Tag + if: steps.check_tag.outputs.exists == 'false' + run: | + TAG="crates/grpc_client/go/v${{ steps.version.outputs.version }}" + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git tag "$TAG" + git push origin "$TAG" diff --git a/crates/grpc_client/go/.gitignore b/crates/grpc_client/go/.gitignore new file mode 100644 index 0000000000..703793fdd6 --- /dev/null +++ b/crates/grpc_client/go/.gitignore @@ -0,0 +1,3 @@ +# Generated files +generated/ +proto/ diff --git a/crates/grpc_client/go/README.md b/crates/grpc_client/go/README.md new file mode 100644 index 0000000000..64ab0d8c46 --- /dev/null +++ b/crates/grpc_client/go/README.md @@ -0,0 +1,45 @@ +# SMG gRPC Client (Go) + +This module contains auto-generated Go gRPC code for Shepherd Model Gateway services (SGLang, vLLM, TRT-LLM). + +## Installation + +To use this module in your Go project: + +```bash +go get github.com/lightseek/smg/crates/grpc_client/go +``` + +## Package Structure + +The generated code is divided into packages under the `generated` directory: + +- `generated/common`: Common types (e.g., KV Events) +- `generated/sglang_encoder`: SGLang Encoder service +- `generated/sglang_scheduler`: SGLang Scheduler service +- `generated/trtllm`: TensorRT-LLM Service +- `generated/vllm`: vLLM Engine service + +## Generation + +To regenerate the code from `.proto` files: + +1. Install prerequisites: + ```bash + go install google.golang.org/protobuf/cmd/protoc-gen-go@latest + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest + ``` +2. Run the generation script: + ```bash + bash generate.sh + ``` + +The generated code is committed to **Git release tags** automatically by the CI pipeline for convenience. + +> [!IMPORTANT] +> When consuming this module in external projects, you **must** specify a version tag (e.g., `@v1.0.0`). Consuming the `main` branch directly will result in missing generated files due to full-tree `.gitignore`. + + +## Release + +Releases are created automatically when the version in the `VERSION` file is updated and merged into `main`. It will create a Git tag: `crates/grpc_client/go/v`. diff --git a/crates/grpc_client/go/VERSION b/crates/grpc_client/go/VERSION new file mode 100644 index 0000000000..6e8bf73aa5 --- /dev/null +++ b/crates/grpc_client/go/VERSION @@ -0,0 +1 @@ +0.1.0 diff --git a/crates/grpc_client/go/generate.go b/crates/grpc_client/go/generate.go new file mode 100644 index 0000000000..62a02d1223 --- /dev/null +++ b/crates/grpc_client/go/generate.go @@ -0,0 +1,3 @@ +// Package go_client is used to trigger code generation. +//go:generate bash ./generate.sh +package go_client diff --git a/crates/grpc_client/go/generate.sh b/crates/grpc_client/go/generate.sh new file mode 100644 index 0000000000..c88e2cb771 --- /dev/null +++ b/crates/grpc_client/go/generate.sh @@ -0,0 +1,114 @@ +#!/bin/bash +set -e + +# Paths +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROTO_SOURCE_DIR="$SCRIPT_DIR/../proto" +GO_PROTO_DIR="$SCRIPT_DIR/proto" +OUTPUT_DIR="$SCRIPT_DIR/generated" + +# Ensure directories exist +mkdir -p "$GO_PROTO_DIR" +rm -rf "$OUTPUT_DIR" +mkdir -p "$OUTPUT_DIR/common" +mkdir -p "$OUTPUT_DIR/sglang_encoder" +mkdir -p "$OUTPUT_DIR/sglang_scheduler" +mkdir -p "$OUTPUT_DIR/trtllm" +mkdir -p "$OUTPUT_DIR/vllm" + +# Copy proto files +echo "Copying proto files..." +cp "$PROTO_SOURCE_DIR"/*.proto "$GO_PROTO_DIR"/ + +# Find tools in PATH or GOPATH +PROTOC_GEN_GO=$(which protoc-gen-go || echo "$(go env GOPATH)/bin/protoc-gen-go") +PROTOC_GEN_GO_GRPC=$(which protoc-gen-go-grpc || echo "$(go env GOPATH)/bin/protoc-gen-go-grpc") + +if [ ! -f "$PROTOC_GEN_GO" ]; then + echo "Error: protoc-gen-go not found. Please install with: go install google.golang.org/protobuf/cmd/protoc-gen-go@latest" + exit 1 +fi + +if [ ! -f "$PROTOC_GEN_GO_GRPC" ]; then + echo "Error: protoc-gen-go-grpc not found. Please install with: go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest" + exit 1 +fi + +# Common mappings for imports +MAPPINGS="--go_opt=Mcommon.proto=github.com/lightseek/smg/crates/grpc_client/go/generated/common" +MAPPINGS_GRPC="--go-grpc_opt=Mcommon.proto=github.com/lightseek/smg/crates/grpc_client/go/generated/common" + +echo "Generating Go code..." + +cd "$GO_PROTO_DIR" + +# Common +protoc \ + --plugin=protoc-gen-go="$PROTOC_GEN_GO" \ + --proto_path=. \ + --go_out="$OUTPUT_DIR/common" \ + --go_opt=paths=source_relative \ + --go_opt=Mcommon.proto=github.com/lightseek/smg/crates/grpc_client/go/generated/common \ + common.proto + +# SGLang Encoder +protoc \ + --plugin=protoc-gen-go="$PROTOC_GEN_GO" \ + --plugin=protoc-gen-go-grpc="$PROTOC_GEN_GO_GRPC" \ + --proto_path=. \ + --go_out="$OUTPUT_DIR/sglang_encoder" \ + --go_opt=paths=source_relative \ + $MAPPINGS \ + --go_opt=Msglang_encoder.proto=github.com/lightseek/smg/crates/grpc_client/go/generated/sglang_encoder \ + --go-grpc_out="$OUTPUT_DIR/sglang_encoder" \ + --go-grpc_opt=paths=source_relative \ + $MAPPINGS_GRPC \ + --go-grpc_opt=Msglang_encoder.proto=github.com/lightseek/smg/crates/grpc_client/go/generated/sglang_encoder \ + sglang_encoder.proto + +# SGLang Scheduler +protoc \ + --plugin=protoc-gen-go="$PROTOC_GEN_GO" \ + --plugin=protoc-gen-go-grpc="$PROTOC_GEN_GO_GRPC" \ + --proto_path=. \ + --go_out="$OUTPUT_DIR/sglang_scheduler" \ + --go_opt=paths=source_relative \ + $MAPPINGS \ + --go_opt=Msglang_scheduler.proto=github.com/lightseek/smg/crates/grpc_client/go/generated/sglang_scheduler \ + --go-grpc_out="$OUTPUT_DIR/sglang_scheduler" \ + --go-grpc_opt=paths=source_relative \ + $MAPPINGS_GRPC \ + --go-grpc_opt=Msglang_scheduler.proto=github.com/lightseek/smg/crates/grpc_client/go/generated/sglang_scheduler \ + sglang_scheduler.proto + +# TRT-LLM Service +protoc \ + --plugin=protoc-gen-go="$PROTOC_GEN_GO" \ + --plugin=protoc-gen-go-grpc="$PROTOC_GEN_GO_GRPC" \ + --proto_path=. \ + --go_out="$OUTPUT_DIR/trtllm" \ + --go_opt=paths=source_relative \ + $MAPPINGS \ + --go_opt=Mtrtllm_service.proto=github.com/lightseek/smg/crates/grpc_client/go/generated/trtllm \ + --go-grpc_out="$OUTPUT_DIR/trtllm" \ + --go-grpc_opt=paths=source_relative \ + $MAPPINGS_GRPC \ + --go-grpc_opt=Mtrtllm_service.proto=github.com/lightseek/smg/crates/grpc_client/go/generated/trtllm \ + trtllm_service.proto + +# vLLM Engine +protoc \ + --plugin=protoc-gen-go="$PROTOC_GEN_GO" \ + --plugin=protoc-gen-go-grpc="$PROTOC_GEN_GO_GRPC" \ + --proto_path=. \ + --go_out="$OUTPUT_DIR/vllm" \ + --go_opt=paths=source_relative \ + $MAPPINGS \ + --go_opt=Mvllm_engine.proto=github.com/lightseek/smg/crates/grpc_client/go/generated/vllm \ + --go-grpc_out="$OUTPUT_DIR/vllm" \ + --go-grpc_opt=paths=source_relative \ + $MAPPINGS_GRPC \ + --go-grpc_opt=Mvllm_engine.proto=github.com/lightseek/smg/crates/grpc_client/go/generated/vllm \ + vllm_engine.proto + +echo "Generation complete!" diff --git a/crates/grpc_client/go/go.mod b/crates/grpc_client/go/go.mod new file mode 100644 index 0000000000..46dbdb74ce --- /dev/null +++ b/crates/grpc_client/go/go.mod @@ -0,0 +1,15 @@ +module github.com/lightseek/smg/crates/grpc_client/go + +go 1.25.0 + +require ( + google.golang.org/grpc v1.79.3 + google.golang.org/protobuf v1.36.11 +) + +require ( + golang.org/x/net v0.48.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/text v0.32.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect +) diff --git a/crates/grpc_client/go/go.sum b/crates/grpc_client/go/go.sum new file mode 100644 index 0000000000..d705bc9b72 --- /dev/null +++ b/crates/grpc_client/go/go.sum @@ -0,0 +1,38 @@ +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= +google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=