跳转至

Lua 独立消费者

在自己的应用中使用已发布的 LuaRocks praxo-core 0.6.0-1,要求 Lua 5.4。 无需检出 PRAXO-CORE 源码、API Key、模型服务或 AxisVela 产品。安装需要 LuaRocks 访问或已有 rock 缓存。

这是扩展语言 starter,只演示 allow/deny 路径,不在四个具备治理负向矩阵的试点语言范围内。

选择边界

适用于需要显式工具范围和 Policy 的嵌入式模型/工具循环。应用仍负责模型访问、真实身份、 持久审批、外部效果和隔离。它不是托管 Agent 平台、持久图引擎或沙箱服务。 选型前阅读何时不应选择 Core。

在新应用安装

luarocks install praxo-core 0.7.0-1

验收时不要把仓库的 language/lua 目录加入 package.path,也不要使用本地 rockspec 或源码检出。starter 里保留源码回退路径,只是为了让本仓库无需 LuaRocks 也能运行同一文件; 真实消费者应安装 rock。

应用源码

以下为 starter.lua,来自受测源码。

local script_dir = (arg and arg[0] and arg[0]:match("^(.*)[/\\][^/\\]*$")) or "."

package.path = table.concat({
  script_dir .. "/../../language/lua/?.lua",
  script_dir .. "/../../language/lua/?/init.lua",
  "language/lua/?.lua",
  "language/lua/?/init.lua",
  "./?.lua",
  package.path,
}, ";")

local agent = require("praxo.agent")
local errors = require("praxo.errors")
local models = require("praxo.models")

local M = {}

local function fixture_model(target)
  return {
    generate = function(request)
      local last = request.messages[#request.messages]
      if last.role == models.TOOL then
        return models.response({ message = models.message_assistant("recorded") })
      end
      local call = models.tool_call({
        id = "record-1",
        name = "record",
        arguments = { target = target },
      })
      return models.response({
        message = models.message_assistant("", { call }),
      })
    end,
  }
end

function M.run_scenario(target)
  local calls = 0
  local registry = agent.tool_registry()
  agent.register_tool(registry, agent.func_tool("record", "Record a target.", function(_arguments)
    calls = calls + 1
    return "recorded"
  end))

  local options = agent.agent_options(fixture_model(target))
  options.tools = registry
  options.allowed_tools = { "record" }
  options.policy = function(action)
    if action.kind == "model.generate" then
      return { allowed = true, reason = "model generation" }
    elseif action.kind == "tool.invoke" then
      return {
        allowed = action.tool_name == "record" and action.arguments.target == "public",
        reason = "only the public target is permitted",
      }
    end
    return { allowed = false, reason = "unsupported action" }
  end

  local ok, result = pcall(agent.run_agent, options,
    models.session({ id = "consumer-" .. target }), "Record the requested target.")
  if not ok then
    return "", calls, errors.code(result)
  end
  return result.output, calls, nil
end

function M.run()
  local output, calls, code = M.run_scenario("public")
  assert(code == nil and output == "recorded" and calls == 1, "allow verification failed")
  print("allow: recorded; effects=1")

  local _, deny_calls, deny_code = M.run_scenario("private")
  assert(deny_code == "AGENT_POLICY_DENIED" and deny_calls == 0, "deny verification failed")
  print("deny: policy rejected; effects=0")
end

return M

验收测试

以下为 test_starter.lua,来自受测源码。

local script_dir = (arg and arg[0] and arg[0]:match("^(.*)[/\\][^/\\]*$")) or "."
local starter = dofile(script_dir .. "/starter.lua")

local output, calls, code = starter.run_scenario("public")
assert(code == nil and output == "recorded" and calls == 1, "allow verification failed")

local _, deny_calls, deny_code = starter.run_scenario("private")
assert(deny_code == "AGENT_POLICY_DENIED" and deny_calls == 0, "deny verification failed")

print("lua consumer tests passed")

验证

luarocks install praxo-core 0.7.0-1
lua test_starter.lua

程序预期输出:

allow: recorded; effects=1
deny: policy rejected; effects=0

模型是确定性 fixture,不是真实 LLM。allowed_tools 限制工具名,Policy 额外检查目标 参数。被拒绝的 private 目标抛出 AGENT_POLICY_DENIED,且不得增加内存计数器。 替换为真实适配器后仍需保留这些测试。

范围

本 starter 仅证明指定 rock 与 fixture 行为,不包含治理负向矩阵,也不证明真实身份、 持久审批、效果对账或隔离。后续参考 Lua 实现指南及 安全模型。