Files
Agent-System-Core/profile.go
weichen 0cb0a40dc8 Add the prompt module contract and profile references
Why: prompts are moving from code into a data library; core needs the
PromptModule/Trigger/Block contract and profiles need an ordered
promptModules reference (empty = default base+env set).

Evidence: unit-covered via backend prompts package tests over this
contract; composite make test green.

Impact: additive contract fields only; no behavior change in core.

Refs: feature/prompt-library task card.
2026-09-30 10:28:59 +00:00

210 lines
6.1 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 core
import "encoding/json"
// 智能体画像(4.7):核心定制机制,全部数据化、可导入导出。
type AgentProfile struct {
ID string `json:"id"`
Owner string `json:"owner,omitempty"` // 租户;空 = 共享(builtin)
Name string `json:"name"`
Description string `json:"description,omitempty"`
Builtin bool `json:"builtin,omitempty"`
Source string `json:"source,omitempty"` // builtin | plugin | user
SystemPrompt string `json:"systemPrompt"`
// PromptModules 引用提示词库模块 ID(有序;空 = 组装默认基座全集)。
// SystemPrompt 兼容保留:非空时作为附加段追加在模块组装结果之后。
PromptModules []string `json:"promptModules,omitempty"`
Model ModelRoute `json:"model"`
Tools ToolPolicy `json:"tools"`
Context ContextPolicy `json:"context"`
HITL HITLPolicy `json:"hitl"`
Budget RunBudget `json:"budget"`
}
// ModelRoute 按用途选择模型(4.7 kind 路由):空串回落到 chat 默认。
type ModelRoute struct {
Chat string `json:"chat,omitempty"`
Lightweight string `json:"lightweight,omitempty"`
Embedding string `json:"embedding,omitempty"`
Rerank string `json:"rerank,omitempty"`
}
// ToolPolicy 三清单:allow/deny 决定可见工具,confirm 强制执行前 HITL 确认。
// 匹配语义:精确名或前缀通配("http.*" 表示 http 前缀);deny 优先于 allow。
type ToolPolicy struct {
Allow []string `json:"allow"` // ["*"] 全部
Deny []string `json:"deny,omitempty"`
Confirm []string `json:"confirm,omitempty"`
}
// ContextPolicy(4.10):ctxasm 的输入;逐版本增加策略项不动组装器接口。
type ContextPolicy struct {
MaxHistoryMessages int `json:"maxHistoryMessages"` // 0 = 默认 40
SummarizeBeyond bool `json:"summarizeBeyond,omitempty"` // 远期;先存标志
MemoryBudgetPct int `json:"memoryBudgetPct,omitempty"` // 注入槽份额上限
KnowledgeBudgetPct int `json:"knowledgeBudgetPct,omitempty"`
MaxToolResultChars int `json:"maxToolResultChars,omitempty"` // 0 = 默认 20000
}
type HITLPolicy struct {
AskOnAmbiguity bool `json:"askOnAmbiguity"`
TimeoutSec *int `json:"timeoutSec,omitempty"`
}
type RunBudget struct {
MaxTokens *int `json:"maxTokens,omitempty"`
MaxToolCalls *int `json:"maxToolCalls,omitempty"`
MaxTurns *int `json:"maxTurns,omitempty"` // LLM 循环轮上限
}
// ToolAllows 判定:deny 优先;allow 含 "*" 或精确/前缀命中。
func (p ToolPolicy) ToolAllowed(name string) bool {
if matchAny(p.Deny, name) {
return false
}
if len(p.Allow) == 0 {
return true
}
return matchAny(p.Allow, name)
}
func (p ToolPolicy) NeedsConfirm(name string) bool {
return matchAny(p.Confirm, name)
}
// matchAny 语义:pattern 精确等于 name,或以 "xxx." 开头表示前缀族(http. → http.*)。
func matchAny(patterns []string, name string) bool {
for _, p := range patterns {
if p == "*" || p == name {
return true
}
if n := len(p); n > 1 && p[n-1] == '.' {
if len(name) > n-1 && name[:n-1] == p[:n-1] {
return true
}
}
}
return false
}
// ---- 设置(4.9)----
type SettingType string
const (
SettingString SettingType = "string"
SettingNumber SettingType = "number"
SettingBool SettingType = "boolean"
SettingEnum SettingType = "enum"
SettingSecret SettingType = "secret"
)
type SettingEffect string
const (
EffectHot SettingEffect = "hot" // 立即生效
EffectNewRun SettingEffect = "new-run" // 仅影响新 run
EffectRestart SettingEffect = "restart" // 需重启
)
// SettingDesc 描述一个设置项;设置页按此渲染并标注生效时机(schema 驱动)。
type SettingDesc struct {
Key string `json:"key"`
Group string `json:"group"` // 分区:models | profiles | tools | knowledge | ui | plugin:<id>
Label string `json:"label"`
Description string `json:"description,omitempty"`
Type SettingType `json:"type"`
Default any `json:"default,omitempty"`
Options []string `json:"options,omitempty"` // enum
Effect SettingEffect `json:"effect"`
Secret bool `json:"secret,omitempty"`
}
// EffectiveSettings 是覆盖链(system → user → project → conversation)深合并结果。
type EffectiveSettings map[string]any
// MergeSettings 深合并:后者覆盖前者;map 递归合并,其它类型直接覆盖(4.9 数组显式覆盖)。
func MergeSettings(base, override map[string]any) map[string]any {
out := make(map[string]any, len(base)+len(override))
for k, v := range base {
out[k] = v
}
for k, v := range override {
if bm, ok := base[k].(map[string]any); ok {
if vm, ok2 := v.(map[string]any); ok2 {
out[k] = MergeSettings(bm, vm)
continue
}
}
out[k] = v
}
return out
}
// GetString/GetBool/GetNumber 读取点路径("models.chat");缺省返回 def。
func (s EffectiveSettings) GetString(path, def string) string {
v, ok := lookupPath(s, path)
if !ok {
return def
}
if str, ok2 := v.(string); ok2 {
return str
}
return def
}
func (s EffectiveSettings) GetBool(path string, def bool) bool {
v, ok := lookupPath(s, path)
if !ok {
return def
}
if b, ok2 := v.(bool); ok2 {
return b
}
return def
}
func (s EffectiveSettings) GetNumber(path string, def float64) float64 {
v, ok := lookupPath(s, path)
if !ok {
return def
}
if f, ok2 := v.(float64); ok2 {
return f
}
return def
}
func lookupPath(m map[string]any, path string) (any, bool) {
parts := splitPath(path)
var cur any = m
for _, p := range parts {
cm, ok := cur.(map[string]any)
if !ok {
return nil, false
}
cur, ok = cm[p]
if !ok {
return nil, false
}
}
return cur, true
}
func splitPath(path string) []string {
var out []string
cur := ""
for i := 0; i < len(path); i++ {
switch path[i] {
case '.':
out = append(out, cur)
cur = ""
default:
cur += string(path[i])
}
}
return append(out, cur)
}
var _ = json.Marshal // 保持 encoding/json 引用(RawMessage 一致性)