Files
smartmate/backend/newAgent/tools/context_tools.go
Losita 66c06eed0a Version: 0.9.45.dev.260427
后端:
1. execute 主链路重构为“上下文工具域 + 主动优化候选闭环”——移除 order_guard,粗排后默认进入主动微调,先诊断再从后端候选中选择 move/swap,避免 LLM 自由全局乱搜
2. 工具体系升级为动态注入协议——新增 context_tools_add / remove、工具域与二级包映射、主动优化白名单;schedule / taskclass / web 工具按域按包暴露,msg0 规则包与 execute 上下文同步重写
3. analyze_health 升级为主动优化唯一裁判入口——补齐 rhythm / tightness / profile / feasibility 指标、候选扫描与复诊打分、停滞信号、forced imperfection 判定,并把连续优化状态写回运行态
4. 任务类能力并入新 Agent 执行链——新增 upsert_task_class 写工具与启动注入事务写入;任务类模型补充学科画像与整天屏蔽配置,粗排支持 excluded_days_of_week,steady 策略改为基于目标位置/单日负载/分散度/缓冲的候选打分
5. 运行态与路由补齐优化模式语义——新增 active tool domain/packs、pending context hook、active optimize only、taskclass 写入回盘快照;区分 first_full / global_reopt / local_adjust,并完善首次粗排后默认 refine 的判定

前端:
6. 助手时间线渲染细化——推理内容改为独立 reasoning block,支持与工具/状态/正文按时序交错展示,自动收口折叠,修正 confirm reject 恢复动作

仓库:
7. newAgent 文档整体迁入 docs/backend,补充主动优化执行规划与顺序约束拆解文档,删除旧调试日志文件

PS:这次科研了2天,总算是有些进展了——LLM永远只适合做选择题、判断题,不适合做开放创新题。
2026-04-27 01:09:37 +08:00

306 lines
8.5 KiB
Go
Raw 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 newagenttools
import (
"encoding/json"
"strings"
"github.com/LoveLosita/smartflow/backend/newAgent/tools/schedule"
)
type contextToolsAddResult struct {
Tool string `json:"tool"`
Success bool `json:"success"`
Action string `json:"action"`
Domain string `json:"domain,omitempty"`
Packs []string `json:"packs,omitempty"`
Mode string `json:"mode,omitempty"`
Message string `json:"message,omitempty"`
Error string `json:"error,omitempty"`
ErrorCode string `json:"error_code,omitempty"`
}
type contextToolsRemoveResult struct {
Tool string `json:"tool"`
Success bool `json:"success"`
Action string `json:"action"`
Domain string `json:"domain,omitempty"`
Packs []string `json:"packs,omitempty"`
All bool `json:"all,omitempty"`
Message string `json:"message,omitempty"`
Error string `json:"error,omitempty"`
ErrorCode string `json:"error_code,omitempty"`
}
// NewContextToolsAddHandler 创建 context_tools_add 工具。
//
// 职责边界:
// 1. 仅负责校验 domain/mode/packs 并返回结构化结果,不直接修改流程状态;
// 2. 真正的“激活态写回”由 execute 节点根据工具结果回写 CommonState
// 3. schedule 支持可选 packstaskclass 目前不支持可选 packs。
func NewContextToolsAddHandler() ToolHandler {
return func(state *schedule.ScheduleState, args map[string]any) string {
_ = state
domain := NormalizeToolDomain(readContextToolString(args["domain"]))
if domain == "" {
return marshalContextToolsAddResult(contextToolsAddResult{
Tool: ToolNameContextToolsAdd,
Success: false,
Action: "reject",
Error: "参数非法domain 仅支持 schedule/taskclass",
ErrorCode: "invalid_domain",
})
}
mode := strings.ToLower(strings.TrimSpace(readContextToolString(args["mode"])))
if mode == "" {
mode = "replace"
}
if mode != "replace" && mode != "merge" {
return marshalContextToolsAddResult(contextToolsAddResult{
Tool: ToolNameContextToolsAdd,
Success: false,
Action: "reject",
Domain: domain,
Error: "参数非法mode 仅支持 replace/merge",
ErrorCode: "invalid_mode",
})
}
packsRaw := readContextToolStringSlice(args["packs"])
packs, errCode, errText := validateContextPacks(domain, packsRaw, false)
if errCode != "" {
return marshalContextToolsAddResult(contextToolsAddResult{
Tool: ToolNameContextToolsAdd,
Success: false,
Action: "reject",
Domain: domain,
Error: errText,
ErrorCode: errCode,
})
}
// schedule 未显式传 packs 时默认启用最小可用包mutation + analyze
if domain == ToolDomainSchedule && len(packsRaw) == 0 {
packs = ResolveEffectiveToolPacks(domain, nil)
}
return marshalContextToolsAddResult(contextToolsAddResult{
Tool: ToolNameContextToolsAdd,
Success: true,
Action: "activate",
Domain: domain,
Packs: packs,
Mode: mode,
Message: "已激活工具域,可继续调用对应业务工具。",
})
}
}
// NewContextToolsRemoveHandler 创建 context_tools_remove 工具。
//
// 职责边界:
// 1. 仅解析 domain/all/packs 语义并返回结构化结果,不直接触碰上下文存储;
// 2. all=true 表示清空动态区业务工具domain+packs 表示移除该域下指定二级包;
// 3. 仅 schedule 支持按 packs 移除,且 core 不允许显式移除。
func NewContextToolsRemoveHandler() ToolHandler {
return func(state *schedule.ScheduleState, args map[string]any) string {
_ = state
all := readContextToolBool(args["all"])
domainRaw := strings.ToLower(strings.TrimSpace(readContextToolString(args["domain"])))
packsRaw := readContextToolStringSlice(args["packs"])
// 兼容写法domain=all 视为清空全部。
if domainRaw == "all" {
all = true
}
if all {
return marshalContextToolsRemoveResult(contextToolsRemoveResult{
Tool: ToolNameContextToolsRemove,
Success: true,
Action: "clear_all",
All: true,
Message: "已移除全部业务工具域,仅保留上下文管理工具。",
})
}
domain := NormalizeToolDomain(domainRaw)
if domain == "" {
return marshalContextToolsRemoveResult(contextToolsRemoveResult{
Tool: ToolNameContextToolsRemove,
Success: false,
Action: "reject",
Error: "参数非法:需提供 domain=schedule/taskclass 或 all=true",
ErrorCode: "invalid_domain",
})
}
packs, errCode, errText := validateContextPacks(domain, packsRaw, true)
if errCode != "" {
return marshalContextToolsRemoveResult(contextToolsRemoveResult{
Tool: ToolNameContextToolsRemove,
Success: false,
Action: "reject",
Domain: domain,
Error: errText,
ErrorCode: errCode,
})
}
if len(packs) > 0 {
return marshalContextToolsRemoveResult(contextToolsRemoveResult{
Tool: ToolNameContextToolsRemove,
Success: true,
Action: "deactivate_packs",
Domain: domain,
Packs: packs,
Message: "已移除指定工具包。",
})
}
return marshalContextToolsRemoveResult(contextToolsRemoveResult{
Tool: ToolNameContextToolsRemove,
Success: true,
Action: "deactivate",
Domain: domain,
Message: "已移除指定工具域。",
})
}
}
func validateContextPacks(domain string, packs []string, forRemove bool) ([]string, string, string) {
normalizedDomain := NormalizeToolDomain(domain)
if normalizedDomain == "" {
return nil, "invalid_domain", "参数非法domain 非法"
}
if len(packs) == 0 {
return nil, "", ""
}
if normalizedDomain == ToolDomainTaskClass {
return nil, "unsupported_packs_for_domain", "参数非法taskclass 暂不支持 packs"
}
normalized := make([]string, 0, len(packs))
seen := make(map[string]struct{}, len(packs))
for _, raw := range packs {
trimmed := strings.TrimSpace(raw)
if trimmed == "" {
continue
}
pack := NormalizeToolPack(normalizedDomain, trimmed)
if pack == "" {
return nil, "invalid_pack", "参数非法:存在不支持的 pack"
}
if IsFixedToolPack(normalizedDomain, pack) {
if forRemove {
return nil, "fixed_pack_forbidden", "参数非法core 为固定包,不允许 remove"
}
return nil, "fixed_pack_forbidden", "参数非法core 为固定包,不允许 add"
}
if _, exists := seen[pack]; exists {
continue
}
seen[pack] = struct{}{}
normalized = append(normalized, pack)
}
if len(normalized) == 0 {
return nil, "invalid_pack", "参数非法packs 为空或无效"
}
return normalized, "", ""
}
func readContextToolString(raw any) string {
text, _ := raw.(string)
return strings.TrimSpace(text)
}
func readContextToolStringSlice(raw any) []string {
switch typed := raw.(type) {
case []string:
out := make([]string, 0, len(typed))
for _, item := range typed {
text := strings.TrimSpace(item)
if text == "" {
continue
}
out = append(out, text)
}
return out
case []any:
out := make([]string, 0, len(typed))
for _, item := range typed {
text, ok := item.(string)
if !ok {
continue
}
text = strings.TrimSpace(text)
if text == "" {
continue
}
out = append(out, text)
}
return out
case string:
text := strings.TrimSpace(typed)
if text == "" {
return nil
}
parts := strings.Split(text, ",")
out := make([]string, 0, len(parts))
for _, part := range parts {
part = strings.TrimSpace(part)
if part == "" {
continue
}
out = append(out, part)
}
return out
default:
return nil
}
}
func readContextToolBool(raw any) bool {
switch v := raw.(type) {
case bool:
return v
case string:
value := strings.ToLower(strings.TrimSpace(v))
return value == "1" || value == "true" || value == "yes"
case float64:
return v != 0
case float32:
return v != 0
case int:
return v != 0
case int8:
return v != 0
case int16:
return v != 0
case int32:
return v != 0
case int64:
return v != 0
default:
return false
}
}
func marshalContextToolsAddResult(result contextToolsAddResult) string {
raw, err := json.Marshal(result)
if err != nil {
return `{"tool":"context_tools_add","success":false,"action":"reject","error":"result encode failed","error_code":"encode_failed"}`
}
return string(raw)
}
func marshalContextToolsRemoveResult(result contextToolsRemoveResult) string {
raw, err := json.Marshal(result)
if err != nil {
return `{"tool":"context_tools_remove","success":false,"action":"reject","error":"result encode failed","error_code":"encode_failed"}`
}
return string(raw)
}