refactor(lua): replaceSDKReal 633 行按 SDK 子表拆分

抽 luaReg 上下文(L/t/plg/s + subTable/pushVal/pushList/pushErr/pushNil
五个助手方法),把单函数拆成 registerRegistrars / registerInjectors /
registerDataAPIs / registerSettings / registerEventsAndMgr 五个方法。

被移动的代码体**逐字保留**:各方法头部把 L/t/s/plg 与五个助手注入为局部
别名,所以内部一行未改,行为零漂移。luaSyncUnavailable 提为包级函数
(原来它在被拆到另一个方法的作用域里会 undefined)。

实测:replaceSDKReal 从 633 行消失,最大子方法 265 行;非测试函数
>=300 行的数量 3→2。go build/vet/test -race 全绿。
This commit is contained in:
HomeAgent Agent
2026-09-13 22:44:39 +08:00
parent 62e1e02036
commit dcae21b24c

View File

@ -226,7 +226,92 @@ func replaceSDKStubs(L *lua.LState, t *lua.LTable, plg *luaPlugin) {
// replaceSDKReal 用真实 SDK 实现替换 sdk 表。
// 此时 plg.handlers/stages 已存有加载期间注册的 handler。
// luaSyncUnavailable 是同步注入(文本/媒体)在 Lua 里的统一应答:立即返回明确错误。
//
// 为何不可用Lua 代码只在 Start / 工具 / 阶段 / 输出通道 / 事件回调里执行,
// 这些路径都持有 plg.mu而 InjectInputSync 要等本轮回复,本轮回复的处理
// (以及回复路径上的阶段/工具回调)又需要同一把锁 ⇒ 必然自锁。
// 与其让插件挂死到超时,不如明确报错:需要同步等待请改用 Go 插件。
func luaSyncUnavailable(L *lua.LState) int {
L.Push(lua.LNil)
L.Push(lua.LString("同步注入在 Lua 插件中不可用:它要等本轮回复,而本轮正持有插件锁 ⇒ 必然自锁。请在事件回调/外部入口用 inject_text / inject_interrupt 异步投递;确需同步等待请改用 Go 插件。"))
return 2
}
// luaReg 承载一次 replaceSDKReal 的注册上下文。
//
// 抽它出来是为了把原来 600+ 行的单函数按 SDK 子表拆开:各子表注册函数
// 共享同一组 push/取表助手,且把 L/t/s/plg 作为局部别名注入,使被移动的
// 代码体可以逐字保留(零改写 = 零行为漂移)。
type luaReg struct {
L *lua.LState
t *lua.LTable
plg *luaPlugin
s *sdk.PluginSDK
}
func (c *luaReg) subTable(name string) *lua.LTable {
if v := c.t.RawGetString(name); v != nil {
if st, ok := v.(*lua.LTable); ok {
return st
}
}
st := c.L.NewTable()
c.t.RawSetString(name, st)
return st
}
func (c *luaReg) pushVal(val interface{}) int {
c.L.Push(jsonToLuaValue(c.L, val))
c.L.Push(lua.LNil)
return 2
}
// pushList 归一化 nil/空 切片与 map 为 Lua 空表。
func (c *luaReg) pushList(val interface{}) int {
if val == nil {
return c.pushVal([]interface{}{})
}
v := reflect.ValueOf(val)
switch v.Kind() {
case reflect.Slice, reflect.Array, reflect.Map:
if v.Len() == 0 {
return c.pushVal([]interface{}{})
}
}
return c.pushVal(val)
}
func (c *luaReg) pushErr(err error) int {
c.L.Push(lua.LNil)
c.L.Push(lua.LString(err.Error()))
return 2
}
func (c *luaReg) pushNil() int {
c.L.Push(lua.LNil)
c.L.Push(lua.LNil)
return 2
}
// replaceSDKReal 用真实 SDK 实现替换 sdk 表。
// 此时 plg 已存有加载期注册的 handler。本函数只做分发各子表见 register*。
func replaceSDKReal(L *lua.LState, t *lua.LTable, plg *luaPlugin, s *sdk.PluginSDK) {
c := &luaReg{L: L, t: t, plg: plg, s: s}
c.registerRegistrars()
c.registerInjectors()
c.registerDataAPIs()
c.registerSettings()
c.registerEventsAndMgr()
}
// registerRegistrars 注册工具/阶段/API/输入输出通道与基础配置读写。
func (c *luaReg) registerRegistrars() {
L, t, s, plg := c.L, c.t, c.s, c.plg
_, _, _, _ = L, t, s, plg
subTable, pushVal, pushList, pushErr, pushNil := c.subTable, c.pushVal, c.pushList, c.pushErr, c.pushNil
_, _, _, _, _ = subTable, pushVal, pushList, pushErr, pushNil
t.RawSetString("register_tool", L.NewFunction(func(L *lua.LState) int {
toolName := L.CheckString(1)
defTbl := L.CheckTable(2)
@ -298,17 +383,7 @@ func replaceSDKReal(L *lua.LState, t *lua.LTable, plg *luaPlugin, s *sdk.PluginS
return 0
}))
// 同步注入(文本/媒体)在 Lua 中**不可用**Lua 代码只在 Start / 工具 /
// 阶段 / 输出通道 / 事件回调里执行,这些路径都持有 plg.mu而 InjectInputSync
// 要等本轮回复,本轮回复的处理(以及回复路径上的阶段/工具回调)又需要同一把
// 锁 ⇒ 必然自锁。返回明确错误,而不是让插件在 30 分钟后超时。
// 需要同步等待的场景请改用 Go 插件(可在自己的 goroutine 里调),
// 或用 inject_text / inject_interrupt 异步投递。
luaSyncUnavailable := func(L *lua.LState) int {
L.Push(lua.LNil)
L.Push(lua.LString("同步注入在 Lua 插件中不可用:它要等本轮回复,而本轮正持有插件锁 ⇒ 必然自锁。请在事件回调/外部入口用 inject_text / inject_interrupt 异步投递;确需同步等待请改用 Go 插件。"))
return 2
}
// 同步注入(文本/媒体)在 Lua 中**不可用**,统一返回明确错误:见 luaSyncUnavailable。
t.RawSetString("inject_text", L.NewFunction(func(L *lua.LState) int {
s.InjectText(L.CheckString(1), L.CheckString(2), L.CheckString(3))
@ -323,6 +398,15 @@ func replaceSDKReal(L *lua.LState, t *lua.LTable, plg *luaPlugin, s *sdk.PluginS
return 0
}))
}
// registerInjectors 注册全部注入接口(文本/中断/媒体/标志位)与通道注销。
func (c *luaReg) registerInjectors() {
L, t, s, plg := c.L, c.t, c.s, c.plg
_, _, _, _ = L, t, s, plg
subTable, pushVal, pushList, pushErr, pushNil := c.subTable, c.pushVal, c.pushList, c.pushErr, c.pushNil
_, _, _, _, _ = subTable, pushVal, pushList, pushErr, pushNil
// ---- 1.2.0 注入标志位no_memory / context_policy / cleaner_name / priority----
t.RawSetString("inject_text_opts", L.NewFunction(func(L *lua.LState) int {
s.InjectTextOpts(L.CheckString(1), L.CheckString(2), L.CheckString(3), parseInjectOptions(L, 4))
@ -374,48 +458,14 @@ func replaceSDKReal(L *lua.LState, t *lua.LTable, plg *luaPlugin, s *sdk.PluginS
return 2
}))
// ---- 数据类 API与 C ABI 外部插件面完全对齐)----
// 约定:结果型返回 (result, err)void 型返回 (nil, err),成功时 err 为 nil。
}
subTable := func(name string) *lua.LTable {
if v := t.RawGetString(name); v != nil {
if st, ok := v.(*lua.LTable); ok {
return st
}
}
st := L.NewTable()
t.RawSetString(name, st)
return st
}
pushVal := func(val interface{}) int {
L.Push(jsonToLuaValue(L, val))
L.Push(lua.LNil)
return 2
}
// pushList 归一化 nil/空 切片与 map 为 Lua 空表。
pushList := func(val interface{}) int {
if val == nil {
return pushVal([]interface{}{})
}
v := reflect.ValueOf(val)
switch v.Kind() {
case reflect.Slice, reflect.Array, reflect.Map:
if v.Len() == 0 {
return pushVal([]interface{}{})
}
}
return pushVal(val)
}
pushErr := func(err error) int {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
pushNil := func() int {
L.Push(lua.LNil)
L.Push(lua.LNil)
return 2
}
// registerDataAPIs 注册 memory/doc/knowledge/text_memory/llm/social 与 set_auto_restart。
func (c *luaReg) registerDataAPIs() {
L, t, s, plg := c.L, c.t, c.s, c.plg
_, _, _, _ = L, t, s, plg
subTable, pushVal, pushList, pushErr, pushNil := c.subTable, c.pushVal, c.pushList, c.pushErr, c.pushNil
_, _, _, _, _ = subTable, pushVal, pushList, pushErr, pushNil
// sdk.set_auto_restart(enabled)
t.RawSetString("set_auto_restart", L.NewFunction(func(L *lua.LState) int {
@ -675,6 +725,15 @@ func replaceSDKReal(L *lua.LState, t *lua.LTable, plg *luaPlugin, s *sdk.PluginS
return pushVal([]interface{}{})
}))
}
// registerSettings 注册 sdk.settings.*(作用域变体与配置项定义)。
func (c *luaReg) registerSettings() {
L, t, s, plg := c.L, c.t, c.s, c.plg
_, _, _, _ = L, t, s, plg
subTable, pushVal, pushList, pushErr, pushNil := c.subTable, c.pushVal, c.pushList, c.pushErr, c.pushNil
_, _, _, _, _ = subTable, pushVal, pushList, pushErr, pushNil
// ---- sdk.settings.* (作用域变体,对齐 CORE_SETTINGS_*) ----
settTbl := subTable("settings")
settTbl.RawSetString("get_core", L.NewFunction(func(L *lua.LState) int {
@ -789,6 +848,15 @@ func replaceSDKReal(L *lua.LState, t *lua.LTable, plg *luaPlugin, s *sdk.PluginS
return pushVal([]interface{}{})
}))
}
// registerEventsAndMgr 注册事件订阅与插件管理面。
func (c *luaReg) registerEventsAndMgr() {
L, t, s, plg := c.L, c.t, c.s, c.plg
_, _, _, _ = L, t, s, plg
subTable, pushVal, pushList, pushErr, pushNil := c.subTable, c.pushVal, c.pushList, c.pushErr, c.pushNil
_, _, _, _, _ = subTable, pushVal, pushList, pushErr, pushNil
// ---- sdk.events.*(只读事件订阅)----
//
// 用内部 SDK 的 Subscribe内置插件用的是同一条路径