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:
61
agent.go
61
agent.go
@@ -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
72
ctx.go
@@ -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
4
go.mod
@@ -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
8
go.sum
@@ -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=
|
||||
|
||||
22
types.go
22
types.go
@@ -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())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user