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 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
- return { name, description, parameters: schema };
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
- props.set(key, { t: "unknown" });
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 (!description) {
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("warn", "name-style", tool.name, "工具名建议用小写 snake_case");
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.0",
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",