1
0
mirror of https://github.com/fumiama/go-onebot-agent.git synced 2026-06-05 02:00:23 +08:00

optimize: use deepinfra.chat

This commit is contained in:
源文雨
2025-09-21 14:44:17 +08:00
parent 1ddb4dfdc5
commit 22d013de83
5 changed files with 35 additions and 132 deletions

View File

@@ -2,60 +2,47 @@ package goba
import (
"encoding/json"
"fmt"
"io"
"github.com/fumiama/deepinfra"
"github.com/fumiama/deepinfra/chat"
"github.com/fumiama/deepinfra/model"
"github.com/pkg/errors"
zero "github.com/wdvxdr1123/ZeroBot"
)
var (
ErrZeroOrNegContextCap = errors.New("ctxcap <= 0")
ErrZeroOrNegEventCap = errors.New("evcap <= 0")
ErrPermissionDenied = errors.New("permission denied")
ErrPermissionDenied = errors.New("permission denied")
)
// Agent is a OneBot event context, it is recommended to create one agent
// per group or per user.
type Agent struct {
log chat.Log[fmt.Stringer]
id int64
nickname, sex string
chars string
ctxcap, evcap int
// 64 bits or 32 bits gap
ctx generalctx
perm *Perm
perm *Perm
}
// NewAgent characteristics 最好是 MD 格式
func NewAgent(id int64, nickname, sex string, characteristics string) Agent {
// NewAgent characteristics 最好是 MD 格式, defaultprompt 是上下文为空时的默认项, 建议为 Event JSON
func NewAgent(
id int64, batchcap, itemscap int,
nickname, sex, characteristics, defaultprompt string,
) Agent {
return Agent{
id: id, nickname: nickname, sex: sex, chars: characteristics,
ctxcap: 16, evcap: 8,
log: chat.NewLog[fmt.Stringer](batchcap, itemscap, "\n", defaultprompt),
}
}
func (ag *Agent) SetContextCap(n int) {
if n <= 0 {
panic(ErrZeroOrNegContextCap)
}
ag.ctxcap = n
func (ag *Agent) AddEvent(grp int64, ev *Event) {
ag.log.Add(grp, ev, false)
}
func (ag *Agent) SetEventCap(n int) {
if n <= 0 {
panic(ErrZeroOrNegEventCap)
}
ag.evcap = n
}
func (ag *Agent) AddEvent(ev *Event) {
addctx(&ag.ctx, ev, ag.ctxcap, ag.evcap)
}
func (ag *Agent) AddRequest(req *zero.APIRequest) {
addctx(&ag.ctx, req, ag.ctxcap, ag.evcap)
func (ag *Agent) AddRequest(grp int64, req *zero.APIRequest) {
ag.log.Add(grp, req, true)
}
// GetAction get OneBot CallAction from LLM and add it to context.
@@ -70,24 +57,15 @@ func (ag *Agent) AddRequest(req *zero.APIRequest) {
// with complete req, caller may decide whether to use this req by themselves.
// Whatever, this req will not be added into the context. You may call
// AddRequest to add it but it is not recommended.
func (ag *Agent) GetAction(api deepinfra.API, m model.Protocol, role PermRole) (
func (ag *Agent) GetAction(api deepinfra.API, p model.Protocol, grp int64, role PermRole, isusersystem bool) (
req zero.APIRequest, err error,
) {
p, err := ag.system(role)
sysp, err := ag.system(role)
if err != nil {
return
}
m.System(p)
ag.ctx.mu.Lock()
for i, evs := range ag.ctx.ctx {
if i%2 == 0 { // is user input
m.User(evs.String())
} else { // is agent callback
m.Assistant(evs.String())
}
}
ag.ctx.mu.Unlock()
m := ag.log.Modelize(p, grp, sysp, isusersystem)
resp, err := api.Request(m)
if err != nil {
@@ -101,7 +79,8 @@ func (ag *Agent) GetAction(api deepinfra.API, m model.Protocol, role PermRole) (
if !ag.perm.allow(role, req.Action) {
err = errors.Wrap(ErrPermissionDenied, req.Action)
} else {
ag.AddRequest(&req)
ag.AddRequest(grp, &req)
}
return
}

72
ctx.go
View File

@@ -1,72 +0,0 @@
package goba
import (
"reflect"
"sync"
"github.com/pkg/errors"
zero "github.com/wdvxdr1123/ZeroBot"
)
var (
ErrInvalidFirstContextType = errors.New("invalid first context type")
)
var (
eventType = reflect.TypeOf(Event{})
// requestType = reflect.TypeOf(zero.APIRequest{})
)
type generalctx struct {
mu sync.Mutex
ctx []events
}
func addctx[T Event | zero.APIRequest](
ctx *generalctx, v *T, ctxcap, evcap int,
) {
ctx.mu.Lock()
defer ctx.mu.Unlock()
typ := reflect.TypeOf(v).Elem()
if len(ctx.ctx) == 0 {
// must triggered by event
if !typ.AssignableTo(eventType) {
panic(errors.Wrap(ErrInvalidFirstContextType, typ.String()))
}
// ctxcap & evcap must > 0, no need to check
evs := make(events, 1, evcap)
evs[0] = v
ctx.ctx = make([]events, 1, ctxcap)
ctx.ctx[0] = evs
return
}
// Get the last events slice
lastEvents := &ctx.ctx[len(ctx.ctx)-1]
// Check if the type matches the first element of the last events
firstElemType := reflect.TypeOf((*lastEvents)[0]).Elem()
if typ.AssignableTo(firstElemType) {
// Same type, add to the last events
if len(*lastEvents) >= evcap {
// Shift elements forward by 1 (discard first element)
copy((*lastEvents)[:], (*lastEvents)[1:])
(*lastEvents)[len(*lastEvents)-1] = any(v)
} else {
*lastEvents = append(*lastEvents, any(v))
}
return
}
// Different type or empty last events, create new events slice
if len(ctx.ctx) >= ctxcap {
// Shift elements forward by 2 (user-assistant pair)
copy(ctx.ctx[:], ctx.ctx[2:])
ctx.ctx = ctx.ctx[:len(ctx.ctx)-2]
}
evs := make(events, 1, evcap)
evs[0] = v
ctx.ctx = append(ctx.ctx, evs)
}

4
go.mod
View File

@@ -4,9 +4,9 @@ go 1.20
require (
github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7
github.com/fumiama/deepinfra v0.0.0-20250910144855-27a4e697106d
github.com/fumiama/deepinfra v0.0.0-20250920170049-e3d1b92cc3a1
github.com/pkg/errors v0.9.1
github.com/wdvxdr1123/ZeroBot v1.8.2-0.20250919145948-e8ffbbc995ac
github.com/wdvxdr1123/ZeroBot v1.8.2-0.20250921063512-13752a73d444
gopkg.in/yaml.v3 v3.0.1
)

8
go.sum
View File

@@ -5,8 +5,8 @@ github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7/go.mod h1:vD7Ra3Q9o
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fumiama/deepinfra v0.0.0-20250910144855-27a4e697106d h1:iGxnST620IHrJ47DXkjzrZJ2rskBogWze+UyvnAxT6g=
github.com/fumiama/deepinfra v0.0.0-20250910144855-27a4e697106d/go.mod h1:wW05PQSn8mo1mZIoa6LBUE+3xIBjkoONvnfPTV5ZOhY=
github.com/fumiama/deepinfra v0.0.0-20250920170049-e3d1b92cc3a1 h1:6PglFpNVm3DalGyRldacW2/v4jGWwn3v3q1tr2PhbVQ=
github.com/fumiama/deepinfra v0.0.0-20250920170049-e3d1b92cc3a1/go.mod h1:wW05PQSn8mo1mZIoa6LBUE+3xIBjkoONvnfPTV5ZOhY=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -22,8 +22,8 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/wdvxdr1123/ZeroBot v1.8.2-0.20250919145948-e8ffbbc995ac h1:XWpJQrUg75qUMwyKZX1jjK4ZziS5R4m/yVv5JCee3/s=
github.com/wdvxdr1123/ZeroBot v1.8.2-0.20250919145948-e8ffbbc995ac/go.mod h1:C86nQ0gIdAri4K2vg8IIQIslt08zzrKMcqYt8zhkx1M=
github.com/wdvxdr1123/ZeroBot v1.8.2-0.20250921063512-13752a73d444 h1:7aYFXzvVr2zuxBvqrGaJb24Z4W12aXBdW8DuE1mteE4=
github.com/wdvxdr1123/ZeroBot v1.8.2-0.20250921063512-13752a73d444/go.mod h1:C86nQ0gIdAri4K2vg8IIQIslt08zzrKMcqYt8zhkx1M=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=

View File

@@ -8,19 +8,6 @@ import (
zero "github.com/wdvxdr1123/ZeroBot"
)
type events []any
func (evs events) String() string {
sb := strings.Builder{}
for _, ev := range evs {
err := json.NewEncoder(&sb).Encode(ev) // has been terminated with '\n'
if err != nil {
panic(errors.Wrap(err, "unexpected"))
}
}
return strings.TrimSpace(sb.String())
}
// Event is the simplified OneBot event that dumped to the agent in JSON format
type Event struct {
Time int64 `json:"time"` // 事件发生的时间戳
@@ -41,3 +28,12 @@ type Event struct {
Sender *zero.User `json:"sender,omitempty"` // 事件发送者个人信息
Message json.RawMessage `json:"message,omitempty"` // JSON 格式的消息内容
}
func (ev *Event) String() string {
sb := strings.Builder{}
err := json.NewEncoder(&sb).Encode(ev)
if err != nil {
panic(errors.Wrap(err, "unexpected"))
}
return strings.TrimSpace(sb.String())
}