Why: Allow consumers to download an immutable module revision without nested source checkouts or local path replacements. Evidence: SELF package tests and the prior canonical-path rejection are recorded in the Dev dependency-workspace task card; remote consumption is replayed against the committed candidate. Impact: Change the module identity and its Go imports while preserving API behavior. Existing historical submodule revisions remain buildable. Refs: Versioned dependencies U1/U3; feature/dependency-workspace
103 lines
3.1 KiB
Go
103 lines
3.1 KiB
Go
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}
|
||
}
|