modelfunction-cli 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/js-tools.js +13 -2
- package/lib/lint.js +8 -2
- package/lib/scan.js +2 -1
- package/lib/suite.js +2 -1
- package/package.json +2 -2
package/lib/js-tools.js
CHANGED
|
@@ -115,7 +115,11 @@ function toolFromObject(node, ctx, preset = {}) {
|
|
|
115
115
|
node.props.has("isEnabled") ||
|
|
116
116
|
node.props.has("searchHint");
|
|
117
117
|
if (!description && Object.keys(schema.properties ?? {}).length === 0 && !toolish) return undefined;
|
|
118
|
-
|
|
118
|
+
// Claude-style tools build the description in `async description()` or a
|
|
119
|
+
// prompt template; lint must not call that "missing".
|
|
120
|
+
const descNode = node.props.get("description");
|
|
121
|
+
const runtimeDescription = !description && (descNode?.t === "unknown" || node.props.has("prompt"));
|
|
122
|
+
return { name, description, parameters: schema, ...(runtimeDescription ? { descriptionSource: "runtime" } : {}) };
|
|
119
123
|
}
|
|
120
124
|
|
|
121
125
|
function isSchema(value) {
|
|
@@ -601,7 +605,14 @@ function parseObject(src, start, depth) {
|
|
|
601
605
|
const skipped = skipToValueEnd(src, i);
|
|
602
606
|
if (skipped === null) {
|
|
603
607
|
return null; }
|
|
604
|
-
|
|
608
|
+
// `async description() {...}` — record the method's real name so lint can
|
|
609
|
+
// tell "description generated at runtime" apart from "no description".
|
|
610
|
+
let methodName = key;
|
|
611
|
+
if ((key === "async" || key === "get" || key === "set") && /[A-Za-z_$]/.test(src[i] ?? "")) {
|
|
612
|
+
const inner = readIdent(src, i);
|
|
613
|
+
if (inner && src[skipTrivia(src, inner.end)] === "(") methodName = inner.name;
|
|
614
|
+
}
|
|
615
|
+
props.set(methodName, { t: "unknown" });
|
|
605
616
|
i = skipped;
|
|
606
617
|
if (src[i] === ",") {
|
|
607
618
|
i += 1;
|
package/lib/lint.js
CHANGED
|
@@ -91,7 +91,11 @@ export function lintSuite(suite) {
|
|
|
91
91
|
const description = (tool.description ?? "").trim();
|
|
92
92
|
const template = `建议:\`${tool.name}:当用户需要____时使用。输入____,返回____。不适用于____。\``;
|
|
93
93
|
|
|
94
|
-
if (
|
|
94
|
+
if (tool.descriptionSource === "runtime") {
|
|
95
|
+
// The description exists at runtime but is assembled in code, so static
|
|
96
|
+
// review cannot judge its wording. Not a defect.
|
|
97
|
+
add("info", "desc-runtime", tool.name, "description 由代码在运行时生成,静态不可评;请确认运行时输出包含触发时机与边界");
|
|
98
|
+
} else if (!description) {
|
|
95
99
|
add("error", "desc-missing", tool.name, "工具没有 description,模型无法判断何时调用", { suggestion: template });
|
|
96
100
|
} else {
|
|
97
101
|
if (description.length < 20) {
|
|
@@ -107,8 +111,10 @@ export function lintSuite(suite) {
|
|
|
107
111
|
}
|
|
108
112
|
}
|
|
109
113
|
|
|
114
|
+
// Naming style is an ecosystem convention, not a model-facing defect:
|
|
115
|
+
// Claude-style PascalCase agents work fine on their own. Info only.
|
|
110
116
|
if (!/^[a-z][a-z0-9_]*$/.test(tool.name)) {
|
|
111
|
-
add("
|
|
117
|
+
add("info", "name-style", tool.name, "工具名不是小写 snake_case;对外分发(MCP/插件市场)时建议统一");
|
|
112
118
|
}
|
|
113
119
|
if (GENERIC_NAMES.has(tool.name)) {
|
|
114
120
|
add("warn", "name-generic", tool.name, "工具名过于通用,容易和其它工具混淆", {
|
package/lib/scan.js
CHANGED
|
@@ -348,7 +348,8 @@ export function buildSuiteDraft(report) {
|
|
|
348
348
|
tools: report.tools.map((tool) => ({
|
|
349
349
|
name: tool.name,
|
|
350
350
|
description: tool.description,
|
|
351
|
-
parameters: tool.parameters
|
|
351
|
+
parameters: tool.parameters,
|
|
352
|
+
...(tool.descriptionSource ? { descriptionSource: tool.descriptionSource } : {})
|
|
352
353
|
})),
|
|
353
354
|
cases: []
|
|
354
355
|
};
|
package/lib/suite.js
CHANGED
|
@@ -54,7 +54,8 @@ async function normalizeTool(entry, baseDir) {
|
|
|
54
54
|
description: entry.description ?? "",
|
|
55
55
|
parameters: entry.parameters ?? entry.input ?? EMPTY_SCHEMA,
|
|
56
56
|
source: null,
|
|
57
|
-
sideEffects: normalizeSideEffects(entry.sideEffects ?? entry.side_effects)
|
|
57
|
+
sideEffects: normalizeSideEffects(entry.sideEffects ?? entry.side_effects),
|
|
58
|
+
...(entry.descriptionSource === "runtime" ? { descriptionSource: "runtime" } : {})
|
|
58
59
|
};
|
|
59
60
|
}
|
|
60
61
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "modelfunction-cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "mf — function-calling accuracy scorecard for AI agents",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"LICENSE"
|
|
26
26
|
],
|
|
27
27
|
"scripts": {
|
|
28
|
-
"test": "node --test \"test/**/*.test.js\"",
|
|
28
|
+
"test": "node --test --test-concurrency=1 \"test/**/*.test.js\"",
|
|
29
29
|
"eval": "node mf.js eval",
|
|
30
30
|
"eval:mock": "node mf.js eval --models mock --show-cases",
|
|
31
31
|
"pack:check": "npm pack --dry-run",
|