Skip to content

Commit 0fa3155

Browse files
authored
Merge pull request #1 from cpunion/chat
add chat interface
2 parents 83e291a + d09c2a6 commit 0fa3155

18 files changed

+784
-2
lines changed

.cursorrules

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
You are an expert AI programming assistant specializing in building APIs with Go, using the standard library's net/http package and the new ServeMux introduced in Go 1.22.
2+
3+
Always use the latest stable version of Go (1.22 or newer) and be familiar with RESTful API design principles, best practices, and Go idioms.
4+
5+
- Follow the user's requirements carefully & to the letter.
6+
- First think step-by-step - describe your plan for the API structure, endpoints, and data flow in pseudocode, written out in great detail.
7+
- Confirm the plan, then write code!
8+
- Write correct, up-to-date, bug-free, fully functional, secure, and efficient Go code for APIs.
9+
- Use the standard library's net/http package for API development:
10+
- Utilize the new ServeMux introduced in Go 1.22 for routing
11+
- Implement proper handling of different HTTP methods (GET, POST, PUT, DELETE, etc.)
12+
- Use method handlers with appropriate signatures (e.g., func(w http.ResponseWriter, r \*http.Request))
13+
- Leverage new features like wildcard matching and regex support in routes
14+
- Implement proper error handling, including custom error types when beneficial.
15+
- Use appropriate status codes and format JSON responses correctly.
16+
- Implement input validation for API endpoints.
17+
- Utilize Go's built-in concurrency features when beneficial for API performance.
18+
- Follow RESTful API design principles and best practices.
19+
- Include necessary imports, package declarations, and any required setup code.
20+
- Implement proper logging using the standard library's log package or a simple custom logger.
21+
- Consider implementing middleware for cross-cutting concerns (e.g., logging, authentication).
22+
- Implement rate limiting and authentication/authorization when appropriate, using standard library features or simple custom implementations.
23+
- Leave NO todos, placeholders, or missing pieces in the API implementation.
24+
- Be concise in explanations, but provide brief comments for complex logic or Go-specific idioms.
25+
- Always use English in comments and code.
26+
- If unsure about a best practice or implementation detail, say so instead of guessing.
27+
- Offer suggestions for testing the API endpoints using Go's testing package.
28+
29+
Always prioritize security, scalability, and maintainability in your API designs and implementations. Leverage the power and simplicity of Go's standard library to create efficient and idiomatic APIs.

.github/workflows/check.yml

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: Test
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
check:
11+
name: Lint
12+
runs-on: ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@v4
15+
16+
- name: Set up Go
17+
uses: actions/setup-go@v4
18+
with:
19+
go-version: '1.22'
20+
cache: true
21+
22+
- name: Set up Node.js
23+
uses: actions/setup-node@v4
24+
with:
25+
node-version: '20'
26+
27+
- name: golangci-lint
28+
uses: golangci/golangci-lint-action@v3
29+
with:
30+
version: latest
31+
32+
- name: Install pre-commit
33+
run: |
34+
python -m pip install --upgrade pip
35+
pip install pre-commit
36+
37+
- name: Install golang checking tools
38+
run: |
39+
go install golang.org/x/tools/cmd/goimports@latest
40+
go install github.com/fzipp/gocyclo/cmd/gocyclo@latest
41+
go install -v github.com/go-critic/go-critic/cmd/gocritic@latest
42+
43+
- name: Install embedme
44+
run: npm install -g embedme
45+
46+
- name: Run pre-commit
47+
run: pre-commit run --all-files

.github/workflows/test.yml

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: Test
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
test:
11+
name: Test
12+
strategy:
13+
matrix:
14+
go-version: ['1.22']
15+
os: [ubuntu-latest, macos-latest, windows-latest]
16+
runs-on: ${{ matrix.os }}
17+
18+
steps:
19+
- uses: actions/checkout@v4
20+
21+
- name: Set up Go
22+
uses: actions/setup-go@v4
23+
with:
24+
go-version: ${{ matrix.go-version }}
25+
cache: true
26+
27+
- name: Check Go Formatting
28+
run: |
29+
if [ "$(gofmt -l . | wc -l)" -gt 0 ]; then
30+
echo "The following files are not formatted correctly:"
31+
gofmt -l .
32+
exit 1
33+
fi
34+
if: runner.os != 'Windows'
35+
36+
- name: Install dependencies
37+
run: go mod download
38+
39+
- name: Test examples
40+
run: go run ./examples/chat
41+
shell: bash
42+
env:
43+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
44+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
45+
46+
- name: Run tests with coverage
47+
run: go test -race -coverprofile=coverage.txt -covermode=atomic ./...
48+
shell: bash
49+
env:
50+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
51+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
52+
53+
- name: Upload coverage reports to Codecov
54+
uses: codecov/codecov-action@v5
55+
with:
56+
token: ${{ secrets.CODECOV_TOKEN }}
57+
fail_ci_if_error: true

.golangci.yml

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
linters:
2+
enable:
3+
- gofmt
4+
- govet
5+
- gosimple
6+
- ineffassign
7+
- staticcheck
8+
- typecheck
9+
- unused
10+
- misspell
11+
- goimports
12+
- revive
13+
14+
linters-settings:
15+
revive:
16+
rules:
17+
- name: exported
18+
severity: warning
19+
disabled: false
20+
21+
run:
22+
deadline: 5m
23+
tests: true

.pre-commit-config.yaml

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# See https://pre-commit.com for more information
2+
# See https://pre-commit.com/hooks.html for more hooks
3+
repos:
4+
- repo: https://github.com/pre-commit/pre-commit-hooks
5+
rev: v5.0.0
6+
hooks:
7+
- id: trailing-whitespace
8+
- id: end-of-file-fixer
9+
- id: check-yaml
10+
- id: check-added-large-files
11+
- repo: https://github.com/dnephin/pre-commit-golang
12+
rev: v0.5.1
13+
hooks:
14+
- id: go-fmt
15+
- id: go-vet
16+
- id: go-imports
17+
- id: go-cyclo
18+
args: [-over=15]
19+
- id: validate-toml
20+
- id: no-go-testing
21+
- id: golangci-lint
22+
- id: go-critic
23+
- id: go-build
24+
- id: go-mod-tidy
25+
- repo: local
26+
hooks:
27+
- id: check-embedme
28+
name: check-embedme
29+
entry: npx embedme
30+
language: system
31+
types: [markdown]
32+
files: .*\.md$

README.md

+13-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22

33
A cross-platform Go library for interacting with multiple AI providers' APIs, inspired by [aisuite](https://github.com/andrewyng/aisuite). Currently supports OpenAI and Anthropic providers with a unified interface.
44

5+
6+
[![Build Status](https://github.com/cpunion/go-aisuite/actions/workflows/test.yml/badge.svg)](https://github.com/cpunion/go-aisuite/actions/workflows/test.yml)
7+
[![codecov](https://codecov.io/github/cpunion/go-aisuite/graph/badge.svg?token=uATQa0RzPL)](https://codecov.io/github/cpunion/go-aisuite)
8+
![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/cpunion/go-aisuite)
9+
[![GitHub commits](https://badgen.net/github/commits/cpunion/go-aisuite)](https://GitHub.com/Naereen/cpunion/go-aisuite/commit/)
10+
[![GitHub release](https://img.shields.io/github/v/tag/cpunion/go-aisuite.svg?label=release)](https://github.com/cpunion/go-aisuite/releases)
11+
[![Go Report Card](https://goreportcard.com/badge/github.com/cpunion/go-aisuite)](https://goreportcard.com/report/github.com/cpunion/go-aisuite)
12+
[![Go Reference](https://pkg.go.dev/badge/github.com/cpunion/go-aisuite.svg)](https://pkg.go.dev/github.com/cpunion/go-aisuite)
13+
14+
515
## Features
616

717
- Unified interface for multiple AI providers
@@ -40,9 +50,9 @@ func main() {
4050
// Initialize client with API keys
4151
c := client.New(&client.APIKey{
4252
// Set your OpenAI API key or leave empty to use environment variable OPENAI_API_KEY
43-
OpenAI: "your-openai-api-key",
53+
OpenAI: "",
4454
// Set your Anthropic API key or leave empty to use environment variable ANTHROPIC_API_KEY
45-
Anthropic: "your-anthropic-api-key",
55+
Anthropic: "",
4656
})
4757

4858
// Make a chat completion request
@@ -54,6 +64,7 @@ func main() {
5464
Content: "Hello, how are you?",
5565
},
5666
},
67+
MaxTokens: 10,
5768
})
5869
if err != nil {
5970
panic(err)

chat.go

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package aisuite
2+
3+
type FunctionCall struct {
4+
Name string
5+
Args string
6+
}
7+
8+
type ToolCall struct {
9+
ID string
10+
Tool string
11+
Function FunctionCall
12+
}
13+
14+
// ChatCompletionMessage is a message in a chat completion request.
15+
16+
type Role string
17+
18+
const (
19+
User Role = "user"
20+
System Role = "system"
21+
Assistant Role = "assistant"
22+
)
23+
24+
type ChatCompletionMessage struct {
25+
Role Role
26+
Content string
27+
}
28+
29+
type ChatCompletionRequest struct {
30+
Model string
31+
Messages []ChatCompletionMessage
32+
MaxTokens int
33+
Stream bool
34+
}
35+
36+
type ChatCompletionChoice struct {
37+
Message ChatCompletionMessage
38+
}
39+
40+
type ChatCompletionResponse struct {
41+
Choices []ChatCompletionChoice
42+
}
43+
44+
// ChatCompletionStreamResponse is the response from a chat completion stream.
45+
46+
type ChatCompletionStreamChoiceDelta struct {
47+
Content string
48+
Role string
49+
FunctionCall *FunctionCall
50+
ToolCalls []ToolCall
51+
Refusal string
52+
}
53+
54+
type ChatCompletionStreamChoice struct {
55+
Delta ChatCompletionStreamChoiceDelta
56+
FinishReason string
57+
}
58+
59+
type ChatCompletionStreamResponse struct {
60+
ID string
61+
Model string
62+
Choices []ChatCompletionStreamChoice
63+
}
64+
65+
type ChatCompletionStream interface {
66+
Recv() (ChatCompletionStreamResponse, error)
67+
Close() error
68+
}

client.go

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package aisuite
2+
3+
import "context"
4+
5+
type Client interface {
6+
ChatCompletion(ctx context.Context, request ChatCompletionRequest) (*ChatCompletionResponse, error)
7+
StreamChatCompletion(ctx context.Context, request ChatCompletionRequest) (ChatCompletionStream, error)
8+
}

client/client.go

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package client
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
8+
"github.com/cpunion/go-aisuite"
9+
"github.com/cpunion/go-aisuite/providers"
10+
_ "github.com/cpunion/go-aisuite/providers/anthropic"
11+
_ "github.com/cpunion/go-aisuite/providers/openai"
12+
)
13+
14+
const (
15+
ErrUnknownProvider = "unknown provider"
16+
)
17+
18+
type APIKey struct {
19+
OpenAI string
20+
Anthropic string
21+
}
22+
23+
type AdaptiveClient struct {
24+
apiKey *APIKey
25+
}
26+
27+
func New(apiKey *APIKey) aisuite.Client {
28+
if apiKey == nil {
29+
apiKey = &APIKey{}
30+
}
31+
return AdaptiveClient{apiKey: apiKey}
32+
}
33+
34+
func (c AdaptiveClient) ChatCompletion(ctx context.Context, request aisuite.ChatCompletionRequest) (*aisuite.ChatCompletionResponse, error) {
35+
client, model := c.getClientAndModel(request.Model)
36+
newReq := request
37+
newReq.Model = model
38+
return client.ChatCompletion(ctx, newReq)
39+
}
40+
41+
func (c AdaptiveClient) StreamChatCompletion(ctx context.Context, request aisuite.ChatCompletionRequest) (aisuite.ChatCompletionStream, error) {
42+
client, model := c.getClientAndModel(request.Model)
43+
newReq := request
44+
newReq.Model = model
45+
return client.StreamChatCompletion(ctx, newReq)
46+
}
47+
48+
func (c AdaptiveClient) getClientAndModel(model string) (aisuite.Client, string) {
49+
toks := strings.SplitN(model, ":", 2)
50+
providerName := toks[0]
51+
provider, ok := providers.GetProvider(providerName)
52+
if !ok {
53+
panic(fmt.Sprintf("%s: %s", ErrUnknownProvider, providerName))
54+
}
55+
var apiKey string
56+
switch providerName {
57+
case "openai":
58+
apiKey = c.apiKey.OpenAI
59+
case "anthropic":
60+
apiKey = c.apiKey.Anthropic
61+
}
62+
return provider.NewClient(apiKey), toks[1]
63+
}

0 commit comments

Comments
 (0)