Files
Agent-System-Backend/internal/profiles/profiles.go
weichen 6532fad4d5
ci / vet-and-test (pull_request) Successful in 1m24s
Merge backend main into the vision branch
Why: the parent sync needs a backend commit that contains both vision routing and the current main pin.
Evidence: incoming pin 80bb123 is an ancestor of origin/main; merge keeps cfde38d.
Impact: backend gitlink can record one resolved commit.
Refs: feature/four-model-vision
2026-10-15 05:49:30 +00:00

143 lines
5.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package profiles 管理智能体画像(4.7):数据化、可导入导出;内置默认画像(T0 基线)。
package profiles
import (
"reflect"
"agent-system-backend/internal/store"
core "agent-system-core"
)
// OwnerDefault 与 store 保持一致的默认租户(内置画像共享,owner=”)。
const OwnerDefault = store.OwnerDefault
const DefaultProfileID = "default"
const FastProfileID = "fast"
const ReasoningProfileID = "reasoning"
const WritingProfileID = "writing"
// defaultSystemPrompt 默认画像不再携带常驻提示词:基座(身份/行为/谨慎/工具/风格)
// 与环境段由提示词库组装(prompts 库 base.*/env.*);文档任务输出要求已技能化
// (task.doc-minutes 等,按触发注入)。SystemPrompt 留空 = 完全走库。
const defaultSystemPrompt = ""
func DefaultProfile() core.AgentProfile {
return core.AgentProfile{
ID: DefaultProfileID,
Name: "通用助手",
Description: "内置默认画像:全部工具可用,HTTP 工具执行前确认(T0 基线)。对话模型由系统设置决定。",
Builtin: true,
Source: "builtin",
SystemPrompt: defaultSystemPrompt,
Model: core.ModelRoute{},
Tools: core.ToolPolicy{Allow: []string{"*"}, Confirm: []string{"http."}},
Context: core.ContextPolicy{MaxHistoryMessages: 40, MaxToolResultChars: 20000},
HITL: core.HITLPolicy{AskOnAmbiguity: true},
// 空预算 = 不限制轮次、工具调用数和输出 token。用户自建画像可以自行设上限。
Budget: core.RunBudget{},
}
}
// BuiltinProfiles 是启动时幂等写入的全部内置画像。模型名是网关模型 ID,
// 端点与密钥沿用系统设置。轻量档留空则回落设置里的轻量模型。
func BuiltinProfiles() []core.AgentProfile {
fast := DefaultProfile()
fast.ID = FastProfileID
fast.Name = "快速助手"
fast.Description = "内置画像:对话和轻量任务都用 qwen3.8-flash,适合短问答和改写。"
fast.Model = core.ModelRoute{Chat: "qwen3.8-flash", Lightweight: "qwen3.8-flash"}
reasoning := DefaultProfile()
reasoning.ID = ReasoningProfileID
reasoning.Name = "深度推理"
reasoning.Description = "内置画像:对话用 ZHIPU/GLM-5.3-FlashX。分诊和校验仍走系统轻量模型。"
reasoning.Model = core.ModelRoute{Chat: "ZHIPU/GLM-5.3-FlashX"}
writing := DefaultProfile()
writing.ID = WritingProfileID
writing.Name = "写作与文档"
writing.Description = "内置画像:对话用 ZHIPU/GLM-5.3-Flash。分诊和校验仍走系统轻量模型。"
writing.Model = core.ModelRoute{Chat: "ZHIPU/GLM-5.3-Flash"}
return []core.AgentProfile{DefaultProfile(), fast, reasoning, writing}
}
func builtinID(id string) bool {
for _, p := range BuiltinProfiles() {
if p.ID == id {
return true
}
}
return false
}
type Service struct{ st *store.Store }
func New(st *store.Store) *Service { return &Service{st: st} }
// EnsureDefault 幂等写入全部内置画像;内置画像只读(Save 拒绝编辑),库中与内置定义
// 有差异的行只可能来自更早版本的内置定义,因此差异时升级为当前内置定义。
func (s *Service) EnsureDefault() error {
for _, p := range BuiltinProfiles() {
if cur, err := s.st.GetProfile(OwnerDefault, p.ID); err == nil {
if reflect.DeepEqual(cur, p) {
continue
}
}
if err := s.st.SaveProfile(p); err != nil {
return err
}
}
return nil
}
func (s *Service) List(owner string) ([]core.AgentProfile, error) { return s.st.ListProfiles(owner) }
func (s *Service) Get(owner, id string) (core.AgentProfile, error) {
p, err := s.st.GetProfile(owner, id)
if err == nil {
return p, nil
}
// 空或未知画像回落默认(T0 行为基线)。
return DefaultProfile(), nil
}
func (s *Service) Save(owner string, p core.AgentProfile) error {
if builtinID(p.ID) {
return errReadOnly("profiles: builtin profile is read-only; duplicate and modify")
}
if p.Tools.Allow == nil {
p.Tools.Allow = []string{"*"}
}
p.Owner = owner
return s.st.SaveProfile(p)
}
func (s *Service) Delete(owner, id string) error {
if builtinID(id) {
return errReadOnly("profiles: builtin profile is read-only")
}
return s.st.DeleteProfile(owner, id)
}
// SaveAccountChecked is the user-facing write path. Builtin profiles remain
// read-only and the Store binds the write to the actor's effective account.
func (s *Service) SaveAccountChecked(actor string, p core.AgentProfile, allowImplicitDefault bool) error {
if p.ID == DefaultProfileID || p.Builtin {
return errReadOnly("profiles: builtin profile is read-only; duplicate and modify")
}
if p.Tools.Allow == nil {
p.Tools.Allow = []string{"*"}
}
p.Owner = actor
return s.st.SaveProfileAccountChecked(actor, p, allowImplicitDefault)
}
func (s *Service) DeleteAccountChecked(actor, id string, allowImplicitDefault bool) error {
return s.st.DeleteProfileAccountChecked(actor, id, allowImplicitDefault)
}
type errReadOnly string
func (e errReadOnly) Error() string { return string(e) }