TypeScript 独立消费者¶
在自己的 Node.js 应用中使用已发布的 @axisvela/praxo-core@0.7.1,要求 Node.js 20
或更新版本。无需检出 PRAXO-CORE 源码、API Key、模型服务或 AxisVela 产品。
安装需要 npm Registry 访问或已有缓存。
选择边界¶
适用于需要显式工具范围与 Policy 的嵌入式模型/工具循环。应用仍负责模型访问、真实身份、 持久审批、外部效果和隔离。它不是托管 Agent 平台、持久图引擎或沙箱服务。 选型前阅读何时不应选择 Core。
创建应用¶
在新的应用目录中创建精确依赖的 package.json,再由锁文件安装:
npm install --save-exact @axisvela/praxo-core@0.7.1
提交生成的 package-lock.json,重复验收使用 npm ci。不要使用 file:、link:、
仓库 URL 或本地路径替换发布包。测试会验证固定版本以及模块是否解析到应用内部。
应用源码¶
以下为 starter.js,直接渲染自受测源码。
const {
Agent,
FuncHook,
Registry,
ROLE_ASSISTANT,
ROLE_TOOL,
PolicyDeniedError,
} = require("@axisvela/praxo-core");
class FixtureModel {
constructor(target) {
this.target = target;
}
async generate(request) {
const last = request.messages[request.messages.length - 1];
if (last.role === ROLE_TOOL) {
return { message: { role: ROLE_ASSISTANT, content: "recorded" } };
}
return {
message: {
role: ROLE_ASSISTANT,
toolCalls: [
{
id: "record-1",
name: "record",
arguments: { target: this.target },
},
],
},
};
}
}
class RecordTool {
constructor() {
this.name = "record";
this.description = "Record a target in an in-memory counter.";
this.risk = "write";
this.parameters = {
type: "object",
required: ["target"],
properties: { target: { type: "string" } },
};
this.calls = 0;
}
async invoke() {
this.calls += 1;
return "recorded";
}
}
function buildAgent(target) {
const tool = new RecordTool();
const tools = new Registry();
tools.register(tool);
const policy = new FuncHook((action) => {
if (action.kind === "model.generate") {
return { allowed: true };
}
if (action.kind === "tool.invoke") {
return {
allowed:
action.toolName === "record" &&
action.arguments?.target === "public",
reason: "only the public target is permitted",
};
}
return { allowed: false, reason: "unsupported action" };
});
const agent = new Agent({
model: new FixtureModel(target),
tools,
maxSteps: 3,
allowedTools: ["record"],
policy,
});
return { agent, tool };
}
async function run(write = (line) => console.log(line)) {
const allowed = buildAgent("public");
const result = await allowed.agent.run(
{ id: "starter-public" },
"Record the requested target."
);
if (result.output !== "recorded" || allowed.tool.calls !== 1) {
throw new Error(
`allow verification failed: output=${JSON.stringify(result.output)} effects=${allowed.tool.calls}`
);
}
write("allow: recorded; effects=1");
const denied = buildAgent("private");
try {
await denied.agent.run(
{ id: "starter-private" },
"Record the requested target."
);
} catch (error) {
if (!(error instanceof PolicyDeniedError)) {
throw error;
}
if (denied.tool.calls !== 0) {
throw new Error(`denied call produced effects=${denied.tool.calls}`);
}
write("deny: policy rejected; effects=0");
return;
}
throw new Error("private target was not denied");
}
if (require.main === module) {
run().catch((error) => {
console.error(error);
process.exitCode = 1;
});
}
module.exports = { buildAgent, run };
验收测试¶
以下为 test_starter.test.js,直接渲染自受测源码。
const assert = require("node:assert/strict");
const path = require("node:path");
const test = require("node:test");
const praxo = require("@axisvela/praxo-core");
const pkg = require("@axisvela/praxo-core/package.json");
const { buildAgent, run } = require("./starter");
const expectedVersion = process.env.PRAXO_EXPECTED_VERSION || "0.7.1";
test("allowed tool executes once", async () => {
const { agent, tool } = buildAgent("public");
const result = await agent.run(
{ id: "test-public" },
"Record the requested target."
);
assert.equal(result.output, "recorded");
assert.equal(tool.calls, 1);
});
test("denied tool has no effect", async () => {
const { agent, tool } = buildAgent("private");
await assert.rejects(
agent.run({ id: "test-private" }, "Record the requested target."),
praxo.PolicyDeniedError
);
assert.equal(tool.calls, 0);
});
test("starter output is deterministic", async () => {
const lines = [];
await run((line) => lines.push(line));
assert.deepEqual(lines, [
"allow: recorded; effects=1",
"deny: policy rejected; effects=0",
]);
});
test("dependency comes from the published package", () => {
assert.equal(pkg.version, expectedVersion);
assert.equal(praxo.SDK_VERSION, pkg.version);
const resolved = require.resolve("@axisvela/praxo-core");
const root = path.resolve(__dirname);
assert.ok(
resolved.startsWith(root + path.sep),
`dependency resolved outside the application: ${resolved}`
);
const dependency = require("./package.json").dependencies["@axisvela/praxo-core"];
assert.equal(dependency, expectedVersion);
assert.ok(!/^(file:|link:|git|https?:)/.test(dependency));
});
验证¶
npm ci --no-audit --no-fund
npm test
node starter.js
程序预期输出:
allow: recorded; effects=1
deny: policy rejected; effects=0
模型是确定性 fixture,不是真实 LLM。allowedTools 限制工具名,Policy 额外检查目标参数。
被拒绝的调用抛出 PolicyDeniedError,不得增加内存效果计数。当前 API 的空允许列表不表示
deny-all。替换为真实模型适配器后仍需保留这些测试。
治理验收¶
governed.test.js 增加五项负向检查:
node --test governed.test.js
| 检查 | 必须结果 |
|---|---|
| 缺少必需 Policy | 应用守卫在运行前拒绝;工具零副作用 |
| 工具范围为空 | 应用守卫拒绝;工具零副作用 |
| Middleware 改变最终参数 | 最终操作重新授权;拒绝阻止副作用 |
| 审批编辑改变参数 | 编辑后的操作重新授权;拒绝阻止副作用 |
| Policy 服务错误 | 运行 fail closed;工具零副作用 |
使用受测源码。 守卫属于应用层:Core 保留普通 nil-policy 行为。这些检查不证明真实身份、持久审批、 效果对账或通用安全 Profile。
这些检查仅证明指定发布包与 fixture 行为,不证明真实模型质量、身份真实性、隔离、持久效果 或生产安全。后续参考TypeScript 实现指南及安全模型。