mirror of
https://github.com/fumiama/go-onebot-agent.git
synced 2026-07-02 09:50:36 +08:00
feat: GetAction return multiple reqs
This commit is contained in:
83
README.md
83
README.md
@@ -13,55 +13,50 @@
|
|||||||
|
|
||||||
## OneBot 11 协议
|
## OneBot 11 协议
|
||||||
> 输入输出均为 JSON 格式的一系列 Object,代表一系列事件或响应,以换行符分隔。
|
> 输入输出均为 JSON 格式的一系列 Object,代表一系列事件或响应,以换行符分隔。
|
||||||
> 所有可能的字段由对应的 Golang 结构体给出。
|
> 所有可能的字段如下,type 由对应的 Golang 类型给出。
|
||||||
|
|
||||||
### 输入
|
### 输入
|
||||||
事件 (Event) 是输入的基本单位,
|
事件 (Event) 是输入的基本单位,
|
||||||
```go
|
|key|type|说明|
|
||||||
type Event struct {
|
|---|---|---|
|
||||||
Time int64 `json:"time"` // 事件发生的时间戳
|
|time|int64|事件发生的时间戳|
|
||||||
PostType string `json:"post_type"` // 上报类型: message / notice / request
|
|post_type|string|上报类型: message / notice / request|
|
||||||
MessageType string `json:"message_type"` // message 类型: group / private
|
|message_type|string|message 类型: group / private|
|
||||||
SubType string `json:"sub_type"` // message 子类型: normal (一般消息) / notice (灰色小字通知)
|
|sub_type|string|message 子类型: normal (一般消息) / notice (灰色小字通知)|
|
||||||
MessageID int64 `json:"message_id"` // 消息 ID, 唯一标识该事件
|
|message_id|int64|消息 ID, 唯一标识该事件|
|
||||||
GroupID int64 `json:"group_id"` // QQ群号
|
|group_id|int64|QQ群号|
|
||||||
UserID int64 `json:"user_id"` // 事件发送者QQ号
|
|user_id|int64|事件发送者QQ号|
|
||||||
TargetID int64 `json:"target_id"`
|
|target_id|int64|后述|
|
||||||
SelfID int64 `json:"self_id"` // 收到事件的QQ号 (你的ID)
|
|self_id|int64|收到事件的QQ号 (你的ID)|
|
||||||
NoticeType string `json:"notice_type,omitempty"`
|
|notice_type|string|后述|
|
||||||
OperatorID int64 `json:"operator_id"` // This field is used for Notice Event
|
|operator_id|int64|For Notice Event|
|
||||||
File *File `json:"file,omitempty"`
|
|file|*File|后述|
|
||||||
RequestType string `json:"request_type,omitempty"`
|
|request_type|string|后述|
|
||||||
Flag string `json:"flag,omitempty"`
|
|flag|string|后述|
|
||||||
Comment string `json:"comment,omitempty"` // This field is used for Request Event
|
|comment|string|For Request Event|
|
||||||
Sender *User `json:"sender,omitempty"` // 事件发送者个人信息
|
|sender|*User|事件发送者个人信息|
|
||||||
Message json.RawMessage `json:"message,omitempty"` // JSON 格式的消息内容
|
|message|json.RawMessage|JSON 格式的消息内容|
|
||||||
}
|
|
||||||
```
|
|
||||||
其中,文件 (File) 标识一个聊天文件,
|
其中,文件 (File) 标识一个聊天文件,
|
||||||
```go
|
|key|type|
|
||||||
type File struct {
|
|---|---|
|
||||||
ID string `json:"id"`
|
|id|string|
|
||||||
Name string `json:"name"`
|
|name|string|
|
||||||
Size int64 `json:"size"`
|
|size|int64|
|
||||||
BusID int64 `json:"busid"`
|
|
||||||
}
|
|
||||||
```
|
|
||||||
用户 (User) 标识一个QQ用户,
|
用户 (User) 标识一个QQ用户,
|
||||||
```go
|
|key|type|说明|
|
||||||
type User struct {
|
|---|---|---|
|
||||||
ID int64 `json:"user_id"`
|
|user_id|int64|用户QQ号|
|
||||||
NickName string `json:"nickname"`
|
|nickname|string|昵称|
|
||||||
Sex string `json:"sex"` // "male"、"female"、"unknown"
|
|sex|string|"male"、"female"、"unknown"|
|
||||||
Age int `json:"age"`
|
|age|int|年龄|
|
||||||
Area string `json:"area"` // 地区
|
|area|string|地区|
|
||||||
// 以下为群聊特有字段
|
|card|string|群名片/备注(群聊特有)|
|
||||||
Card string `json:"card"` // 群名片/备注
|
|title|string|专属头衔(群聊特有)|
|
||||||
Title string `json:"title"` // 专属头衔
|
|level|string|群聊等级(群聊特有)|
|
||||||
Level string `json:"level"` // 群聊等级
|
|role|string|"owner"、"admin"、"member"(群聊特有)|
|
||||||
Role string `json:"role"` // "owner"、"admin"、"member"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
#### 详细事件种类
|
#### 详细事件种类
|
||||||
|
|
||||||
|类型|post_type|message_type|sub_type|message_id|group_id|user_id|target_id|self_id|notice_type|operator_id|file|request_type|flag|comment|sender|message|
|
|类型|post_type|message_type|sub_type|message_id|group_id|user_id|target_id|self_id|notice_type|operator_id|file|request_type|flag|comment|sender|message|
|
||||||
|
|||||||
51
agent.go
51
agent.go
@@ -4,7 +4,7 @@ package goba
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"strings"
|
||||||
|
|
||||||
"github.com/fumiama/deepinfra"
|
"github.com/fumiama/deepinfra"
|
||||||
"github.com/fumiama/deepinfra/chat"
|
"github.com/fumiama/deepinfra/chat"
|
||||||
@@ -26,16 +26,23 @@ type Agent struct {
|
|||||||
nickname, sex string
|
nickname, sex string
|
||||||
chars string
|
chars string
|
||||||
perm *Perm
|
perm *Perm
|
||||||
|
manualaddreq bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAgent characteristics 最好是 MD 格式, defaultprompt 是上下文为空时的默认项, 建议为 Event JSON
|
// NewAgent 创建一个 Agent 实例。
|
||||||
|
//
|
||||||
|
// - characteristics 推荐使用 Markdown 格式,描述 Agent 个性。
|
||||||
|
// - defaultprompt 为上下文为空时的默认提示,建议为事件的 JSON,一般不会用到,因此也可留空。
|
||||||
|
// - manualaddreq 表示是否由用户手动添加请求。
|
||||||
func NewAgent(
|
func NewAgent(
|
||||||
id int64, batchcap, itemscap int,
|
id int64, batchcap, itemscap int,
|
||||||
nickname, sex, characteristics, defaultprompt string,
|
nickname, sex, characteristics, defaultprompt string,
|
||||||
|
manualaddreq bool,
|
||||||
) (ag Agent) {
|
) (ag Agent) {
|
||||||
ag = Agent{
|
ag = Agent{
|
||||||
id: id, nickname: nickname, sex: sex, chars: characteristics,
|
id: id, nickname: nickname, sex: sex, chars: characteristics,
|
||||||
log: chat.NewLog[fmt.Stringer](batchcap, itemscap, "\n", defaultprompt),
|
log: chat.NewLog[fmt.Stringer](batchcap, itemscap, "\n", defaultprompt),
|
||||||
|
manualaddreq: manualaddreq,
|
||||||
}
|
}
|
||||||
_ = ag.LoadPermTable()
|
_ = ag.LoadPermTable()
|
||||||
return
|
return
|
||||||
@@ -55,16 +62,12 @@ func (ag *Agent) AddRequest(grp int64, req *zero.APIRequest) {
|
|||||||
//
|
//
|
||||||
// Note:
|
// Note:
|
||||||
//
|
//
|
||||||
// 1. The response may be empty, meaning that LLM do not want
|
// - If LLM returns an invalid action, ErrPermissionDenied will be returned
|
||||||
// to react with these events. In this case, this function will
|
// with complete reqs before invalid call, caller may decide whether to use
|
||||||
// return io.EOF and the context will be left no change.
|
// these reqs by themselves. Whatever, invalid req will not be added into
|
||||||
//
|
// the context. You may call AddRequest to add it but it is not recommended.
|
||||||
// 2. If LLM returns an invalid action, ErrPermissionDenied will be returned
|
|
||||||
// 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, p model.Protocol, grp int64, role PermRole, isusersystem bool) (
|
func (ag *Agent) GetAction(api deepinfra.API, p model.Protocol, grp int64, role PermRole, isusersystem bool) (
|
||||||
req zero.APIRequest, err error,
|
reqs []zero.APIRequest, err error,
|
||||||
) {
|
) {
|
||||||
sysp, err := ag.system(role)
|
sysp, err := ag.system(role)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -77,15 +80,25 @@ func (ag *Agent) GetAction(api deepinfra.API, p model.Protocol, grp int64, role
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = json.Unmarshal([]byte(resp), &req)
|
reqs = make([]zero.APIRequest, 0, 2)
|
||||||
if err == nil && req.Action == "" {
|
dec := json.NewDecoder(strings.NewReader(resp))
|
||||||
err = io.EOF
|
for dec.More() {
|
||||||
|
r := zero.APIRequest{}
|
||||||
|
err = dec.Decode(&r)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
if r.Action == "" {
|
||||||
if !ag.perm.allow(role, req.Action) {
|
continue
|
||||||
err = errors.Wrap(ErrPermissionDenied, req.Action)
|
}
|
||||||
} else {
|
switch {
|
||||||
ag.AddRequest(grp, &req)
|
case !ag.perm.allow(role, r.Action):
|
||||||
|
err = errors.Wrap(ErrPermissionDenied, r.Action)
|
||||||
|
return
|
||||||
|
case !ag.manualaddreq:
|
||||||
|
ag.AddRequest(grp, &r)
|
||||||
|
}
|
||||||
|
reqs = append(reqs, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|||||||
8
types.go
8
types.go
@@ -13,14 +13,14 @@ type Event struct {
|
|||||||
Time int64 `json:"time"` // 事件发生的时间戳
|
Time int64 `json:"time"` // 事件发生的时间戳
|
||||||
PostType string `json:"post_type"` // 上报类型: message / notice / request
|
PostType string `json:"post_type"` // 上报类型: message / notice / request
|
||||||
MessageType string `json:"message_type"` // message 类型: group / private
|
MessageType string `json:"message_type"` // message 类型: group / private
|
||||||
SubType string `json:"sub_type"` // message 子类型: normal (一般消息) / notice (灰色小字通知)
|
SubType string `json:"sub_type,omitempty"` // message 子类型: normal (一般消息) / notice (灰色小字通知)
|
||||||
MessageID int64 `json:"message_id"` // 消息 ID, 唯一标识该事件
|
MessageID int64 `json:"message_id"` // 消息 ID, 唯一标识该事件
|
||||||
GroupID int64 `json:"group_id"` // QQ群号
|
GroupID int64 `json:"group_id,omitempty"` // QQ群号
|
||||||
UserID int64 `json:"user_id"` // 事件发送者QQ号
|
UserID int64 `json:"user_id"` // 事件发送者QQ号
|
||||||
TargetID int64 `json:"target_id"`
|
TargetID int64 `json:"target_id,omitempty"`
|
||||||
SelfID int64 `json:"self_id"` // 收到事件的QQ号 (你的ID)
|
SelfID int64 `json:"self_id"` // 收到事件的QQ号 (你的ID)
|
||||||
NoticeType string `json:"notice_type,omitempty"`
|
NoticeType string `json:"notice_type,omitempty"`
|
||||||
OperatorID int64 `json:"operator_id"` // This field is used for Notice Event
|
OperatorID int64 `json:"operator_id,omitempty"` // This field is used for Notice Event
|
||||||
File *zero.File `json:"file,omitempty"`
|
File *zero.File `json:"file,omitempty"`
|
||||||
RequestType string `json:"request_type,omitempty"`
|
RequestType string `json:"request_type,omitempty"`
|
||||||
Flag string `json:"flag,omitempty"`
|
Flag string `json:"flag,omitempty"`
|
||||||
|
|||||||
Reference in New Issue
Block a user