mirror of
https://github.com/mudler/LocalAI.git
synced 2026-11-06 12:33:16 -05:00
Add the github add-on: manifest with a credential slot, a read-only tool set (code search, files, trees, issues, pull requests and diffs) with size caps and untrusted-content framing, rate-limit mapping, a connector route that checks the token, and a fake GitHub API for tests. Assisted-by: Claude:claude-sonnet-5-5 [go]
79 lines
2.5 KiB
Go
79 lines
2.5 KiB
Go
// SPDX-License-Identifier: MIT
|
|
|
|
// Package platform is the connector route of the GitHub add-on. In this
|
|
// version it carries no messages: a binding of kind github holds the token and
|
|
// the repository list that the read tools use, and the host's Test call asks
|
|
// "me" to check the token. Listening for mentions comes later, so poll waits
|
|
// and returns nothing, and the ops that send fail with a plain reason.
|
|
package platform
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/mudler/LocalAI/addons/github/internal/ghapi"
|
|
"github.com/mudler/LocalAI/addons/internal/connector"
|
|
"github.com/mudler/LocalAI/pkg/addons/contract"
|
|
)
|
|
|
|
// Kind is the one kind of binding this add-on serves.
|
|
const Kind = "github"
|
|
|
|
// ErrNoMessages is what the ops that send answer until the connector exists.
|
|
var ErrNoMessages = errors.New("this add-on does not carry messages yet")
|
|
|
|
// Platform is GitHub as a connector.Platform.
|
|
type Platform struct{ API *ghapi.Client }
|
|
|
|
var _ connector.Platform = Platform{}
|
|
|
|
func (Platform) Kind() string { return Kind }
|
|
func (Platform) MaxRunes() int { return 65000 }
|
|
|
|
// Poll returns no update. It waits for the time the host allows so the loop
|
|
// of an enabled binding does not spin.
|
|
func (Platform) Poll(ctx context.Context, _ string, _ int64, wait int) ([]contract.ConnectorMessage, error) {
|
|
if wait <= 0 {
|
|
return nil, nil
|
|
}
|
|
t := time.NewTimer(time.Duration(wait) * time.Second)
|
|
defer t.Stop()
|
|
select {
|
|
case <-ctx.Done():
|
|
return nil, ctx.Err()
|
|
case <-t.C:
|
|
return nil, nil
|
|
}
|
|
}
|
|
|
|
func (Platform) Send(context.Context, contract.ConnectorRequest) (string, error) {
|
|
return "", ErrNoMessages
|
|
}
|
|
func (Platform) Edit(context.Context, contract.ConnectorRequest) error { return ErrNoMessages }
|
|
func (Platform) Typing(context.Context, contract.ConnectorRequest) error { return nil }
|
|
|
|
// Me returns the login of the token.
|
|
func (p Platform) Me(ctx context.Context, token string) (connector.Bot, error) {
|
|
var me struct {
|
|
ID int64 `json:"id"`
|
|
Login string `json:"login"`
|
|
}
|
|
if _, err := p.API.GetJSON(ctx, token, "/user", nil, &me); err != nil {
|
|
return connector.Bot{}, mapErr(err)
|
|
}
|
|
return connector.Bot{ID: strconv.FormatInt(me.ID, 10), Username: me.Login}, nil
|
|
}
|
|
|
|
func mapErr(err error) error {
|
|
var limited *contract.ErrRateLimited
|
|
switch {
|
|
case errors.Is(err, ghapi.ErrUnauthorized):
|
|
return connector.ErrUnauthorized
|
|
case errors.As(err, &limited):
|
|
return &connector.RetryAfter{Seconds: limited.Seconds()}
|
|
}
|
|
return errors.New(ghapi.Describe(err))
|
|
}
|