mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-11-01 14:57:38 +00:00
时间线此前只写「→ 调用工具: a, b」,工具取回的正文下一轮彻底消失: 模型记得自己查过,却不记得查到了什么(刚说的话转头就忘)。 ToolDef 上的 Cleaner / NoMemory 声明一直存在,缺的是消费端。 - formatMergedTimeline 渲染 e.ToolResults:Cleaner 优先,NoMemory 工具跳过, 单条 160 字、每事件最多 3 条(+N more),预算估算同步计入 - 模态能力改由配置层声明(ProviderManager.SetCapabilities), 不再靠 provider.(ModalProvider) 断言穿过 adapter 与安全装饰器 - a2a 通道 RecallPolicy none→auto(NoMemory 仍 true:可读不写)
63 lines
2.2 KiB
Go
63 lines
2.2 KiB
Go
package api
|
||
|
||
// 模态能力必须由**配置层**声明,而不是靠 adapter 的类型断言去猜。
|
||
//
|
||
// 现场(反复出现的"配了视觉却说没有视觉"):内核用
|
||
// `provider.(ModalProvider)` 断言判定能力,而该断言要穿过 adapter 与
|
||
// 安全装饰器两层 —— 任一层漏实现方法,能力就静默变成 false。
|
||
//
|
||
// 用户指正(2026-10-27):是否支持视觉是**配置事实**
|
||
//(core.llm.sources.<name>.vision=true),adapter 只负责格式转换。
|
||
|
||
import (
|
||
"context"
|
||
"testing"
|
||
)
|
||
|
||
// plainProvider 故意**不实现** ModalProvider —— 模拟"装饰器漏方法"的情形。
|
||
type plainProvider struct{ name string }
|
||
|
||
func (p *plainProvider) Name() string { return p.name }
|
||
func (p *plainProvider) MaxContextTokens() int { return 8192 }
|
||
func (p *plainProvider) Chat(ctx context.Context, req *CompletionRequest) (*CompletionResponse, error) {
|
||
return nil, nil
|
||
}
|
||
|
||
func (p *plainProvider) ChatStream(ctx context.Context, req *CompletionRequest) (<-chan StreamChunk, error) {
|
||
ch := make(chan StreamChunk)
|
||
close(ch)
|
||
return ch, nil
|
||
}
|
||
|
||
func TestProviderManagerCapsDeclaredByConfig(t *testing.T) {
|
||
m := NewProviderManager()
|
||
p := &plainProvider{name: "proxy"}
|
||
m.Register("proxy", p)
|
||
|
||
// 断言兜底:plainProvider 不是 ModalProvider ⇒ false
|
||
if ProviderSupportsVision(p) {
|
||
t.Fatal("前提不成立:plainProvider 不该被断言成支持视觉")
|
||
}
|
||
// 配置声明后 ⇒ true(这就是"配置层说了算")
|
||
m.SetCapabilities("proxy", ProviderCaps{Vision: true})
|
||
if !m.SupportsVision("proxy") {
|
||
t.Fatal("配置声明 vision=true 后应判定为支持视觉,不能因为 provider 没实现 ModalProvider 就丢掉能力")
|
||
}
|
||
if m.SupportsAudio("proxy") {
|
||
t.Fatal("未声明 audio 时不应判定支持音频")
|
||
}
|
||
}
|
||
|
||
func TestProviderManagerCapsFallBackToAssertion(t *testing.T) {
|
||
m := NewProviderManager()
|
||
p := &plainProvider{name: "legacy"}
|
||
m.Register("legacy", p)
|
||
// 没声明(ok=false)⇒ 退回旧路径的断言结果
|
||
if _, ok := m.Capabilities("legacy"); ok {
|
||
t.Fatal("未声明时 Capabilities 应返回 ok=false")
|
||
}
|
||
if m.SupportsVision("legacy") {
|
||
t.Fatal("未声明且非 ModalProvider 时应为 false")
|
||
}
|
||
}
|