package runtime import ( "strings" core "git-ssh.u1680832.nyat.app/weichen/Agent-System-Core.git" ) // SecretLookup 由组合根注入。返回该服务当前生效的明文;没有独立密钥时 ok 为 false,调用方用设置里的旧字段。 var SecretLookup func(owner, service string) (string, bool) // LookupSecret 给组合根以外的调用方使用。owner 为空时用 local。 func LookupSecret(owner, service, fallback string) string { return overlayKey(owner, service, fallback) } func overlayKey(owner, service, fallback string) string { if SecretLookup == nil { return fallback } if owner == "" { owner = "local" } if v, ok := SecretLookup(owner, service); ok && strings.TrimSpace(v) != "" { return v } return fallback } // 模型路由解析(4.7 / 4.9 覆盖链):设置层 defaults → system → user → project, // 画像 ModelRoute 为会话内最高层覆盖(kind 为空回落设置层主模型)。 // 端点与密钥按 kind 独立配置,轻量档空则回落主档。 // ContextInjection 是一条条件注入,由 runmgr 从存储读出,组装时再转换成 ctxasm 的形状。 type ContextInjection struct { Keys []string Secondary string Logic string Content string Constant bool ScanDepth int BudgetChars int } // ResolvedModel 是一次路由解析的结果。 type ResolvedModel struct { Kind string // chat | lightweight Model string Base string Key string } // ResolveChatModel 解析主对话模型(画像 route > 设置层)。 func ResolveChatModel(prof core.AgentProfile, eff core.EffectiveSettings) ResolvedModel { m := eff.GetString("models.chat.model", "") if prof.Model.Chat != "" { m = prof.Model.Chat } return ResolvedModel{Kind: "chat", Model: m, Base: eff.GetString("models.chat.baseUrl", ""), Key: overlayKey(prof.Owner, "models.chat", eff.GetString("models.chat.apiKey", ""))} } // ChatFallbacks 解析 models.chat.fallbacks。默认空,不改变现有模型选择。 func ChatFallbacks(eff core.EffectiveSettings) []string { raw := strings.TrimSpace(eff.GetString("models.chat.fallbacks", "")) if raw == "" { return nil } var out []string seen := map[string]bool{} for _, part := range strings.Split(raw, ",") { name := strings.TrimSpace(part) if name == "" || seen[name] { continue } seen[name] = true out = append(out, name) } return out } // ResolveLightweightModel 解析轻量模型:画像 route > 设置层轻量档 > 回落主档。 func ResolveLightweightModel(prof core.AgentProfile, eff core.EffectiveSettings) ResolvedModel { m := eff.GetString("models.lightweight.model", "") base := eff.GetString("models.lightweight.baseUrl", "") key := overlayKey(prof.Owner, "models.lightweight", eff.GetString("models.lightweight.apiKey", "")) if prof.Model.Lightweight != "" { m = prof.Model.Lightweight } if m == "" || base == "" { // 回落主档(模型与端点分别回落,允许轻量仅覆盖模型名)。 chat := ResolveChatModel(prof, eff) if m == "" { m = chat.Model } if base == "" { base, key = chat.Base, chat.Key } } return ResolvedModel{Kind: "lightweight", Model: m, Base: base, Key: key} }