Skip to content

fix(core): align monitor limit parameter schemas#6413

Merged
wenshao merged 2 commits into
QwenLM:mainfrom
VectorPeak:codex/monitor-schema-integers
Jul 7, 2026
Merged

fix(core): align monitor limit parameter schemas#6413
wenshao merged 2 commits into
QwenLM:mainfrom
VectorPeak:codex/monitor-schema-integers

Conversation

@VectorPeak

@VectorPeak VectorPeak commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

This is mostly a schema-alignment PR rather than a runtime bug fix. The monitor runtime validator already rejects fractional values for these fields, so maintainers should feel free to accept this as a small consistency improvement or close it if the current runtime-only guard is considered sufficient.

What this PR does

This PR changes the monitor tool schema for max_events and idle_timeout_ms from number to integer, matching the validation behavior that already requires both values to be positive integers. It also adds a focused schema assertion so the declaration stays aligned with the runtime validation contract.

Why it's needed

max_events and idle_timeout_ms are discrete limits: one is an event count, and the other is a millisecond timeout value. The monitor validator already treats them that way by rejecting non-integer values with max_events must be a positive integer. and idle_timeout_ms must be a positive integer.

Before this change, the public tool schema still exposed both fields as number. That could make tool callers believe fractional values were schema-valid even though the monitor tool would reject them at runtime. This PR makes the schema describe the same contract that the validator already enforces.

This does not expand monitor behavior or change process lifetime handling. It only tightens the declared parameter shape for values that were already invalid at the tool boundary.

Reviewer Test Plan

How to verify

A reviewer can confirm that the monitor schema now declares max_events and idle_timeout_ms as integer, while the existing runtime validation still rejects invalid fractional or non-positive values. The new unit test covers the schema contract directly, and the existing monitor validation tests continue to cover the runtime guard.

Evidence (Before & After)

Before:

max_events: {
  type: 'number',
}
idle_timeout_ms: {
  type: 'number',
}

After:

max_events: {
  type: 'integer',
}
idle_timeout_ms: {
  type: 'integer',
}

Runtime behavior was already protected by Number.isInteger(...), so the visible behavior for invalid fractional values is unchanged: they remain rejected.

Tested on

OS Status
🍎 macOS ⚪ not tested
🪟 Windows ✅ tested
🐧 Linux ✅ tested

Environment (optional)

Windows local validation used Node.js v24.15.0 / npm 11.12.1. WSL validation used Ubuntu-22.04 with Node.js v24.15.0 / npm 11.12.1.

Commands run on Windows:

cd packages/core && npx vitest run src/tools/monitor.test.ts
npm run build --workspace=packages/core
git diff --check

Results on Windows:

src/tools/monitor.test.ts: 74 tests passed
packages/core build: passed
git diff --check: passed

Commands run on WSL Ubuntu-22.04:

cd packages/core && npx vitest run src/tools/monitor.test.ts --pool forks --poolOptions.forks.singleFork=true
npm run build --workspace=packages/core

Results on WSL Ubuntu-22.04:

src/tools/monitor.test.ts: 74 tests passed
packages/core build: passed

Risk & Scope

  • Main risk or tradeoff: Very low. This only aligns schema metadata with existing validation, but it may make fractional tool calls fail earlier during schema-aware generation/validation instead of reaching the monitor validator.
  • Not validated / out of scope: macOS local runs were not performed. No TUI/media evidence is included because this is a schema metadata alignment with no UI behavior change.
  • Breaking changes / migration notes: No supported integer usage changes. Fractional values were already rejected by runtime validation.

Linked Issues

N/A — no linked issue. This is a small consistency cleanup discovered during local tool-schema review.

中文说明

这更多是一个 schema 对齐 PR,而不是运行时 bug 修复。monitor 的运行时校验已经会拒绝小数,所以 maintainer 如果认为当前运行时保护已经足够,也完全可以不接受这个 PR。

What this PR does

这个 PR 将 monitor 工具的 max_eventsidle_timeout_ms schema 从 number 改成 integer,使它们和已有运行时校验保持一致。PR 也补了一个聚焦的 schema 断言,防止后续声明再次和校验语义分离。

Why it's needed

max_eventsidle_timeout_ms 都是离散限制:一个是事件数量,另一个是毫秒超时时间。monitor validator 当前已经通过 Number.isInteger(...) 要求它们必须是正整数,并会返回 max_events must be a positive integer. / idle_timeout_ms must be a positive integer.

修改前,公开 tool schema 仍然把这两个字段声明为 number。这会让 schema-aware 的调用方误以为小数是合法输入,但运行时又会拒绝它们。这个 PR 只是让 schema 描述和 validator 已经执行的契约一致。

这不会扩展 monitor 行为,也不会改变后台进程生命周期管理。它只收紧两个本来就不合法的参数声明。

Reviewer Test Plan

How to verify

Reviewer 可以确认 monitor schema 现在将 max_eventsidle_timeout_ms 声明为 integer,同时现有运行时校验仍然拒绝非法小数或非正数。新增测试直接覆盖 schema 契约,已有 monitor validation 测试继续覆盖运行时保护。

Evidence (Before & After)

修改前:两个字段声明为 number。修改后:两个字段声明为 integer。运行时行为本来就由 Number.isInteger(...) 保护,因此非法小数的可见行为不变,仍然会被拒绝。

Tested on

Windows 和 WSL Ubuntu-22.04 已测试;macOS 未本地测试。Windows 验证命令为 cd packages/core && npx vitest run src/tools/monitor.test.tsnpm run build --workspace=packages/coregit diff --check,结果均通过。WSL Ubuntu-22.04 验证命令为 cd packages/core && npx vitest run src/tools/monitor.test.ts --pool forks --poolOptions.forks.singleFork=truenpm run build --workspace=packages/core,结果均通过。

Risk & Scope

主要风险很低:这只让 schema metadata 和已有 validation 对齐。唯一变化是 schema-aware 的调用链可能更早识别小数输入非法,而不是等到 monitor validator 再拒绝。没有支持的整数用法会改变,小数值此前也已经不是有效输入。

Linked Issues

N/A — 这是本地 tool-schema review 中发现的小一致性修复,没有关联 issue。

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓ — all required sections present and filled in.

Problem: This is a real, observable inconsistency — the public tool schema declares max_events and idle_timeout_ms as number, but the runtime validator rejects anything that isn't a positive integer via Number.isInteger(). Tool callers that inspect the schema would legitimately believe fractional values are valid, only to get rejected at runtime. Not a runtime bug, but a real contract mismatch at the schema boundary.

Direction: Aligned. Schema accuracy is a core concern for tool callers, and aligning the declared type with the enforced type is straightforward and correct. No CHANGELOG reference needed — this is a small consistency fix.

Size: 2 production lines changed (number → integer, twice), 11 test lines added. Not applicable for size thresholds.

Approach: Scope is exactly right — two type changes in the schema plus a focused test assertion to prevent regression. No drive-by changes, no scope creep. This is what a minimal fix looks like.

Moving on to code review. 🔍

中文说明

感谢贡献!

模板完整 ✓ — 所有必填部分齐全。

问题:这是一个真实存在的、可观测的不一致——公开 tool schema 把 max_eventsidle_timeout_ms 声明为 number,但运行时校验通过 Number.isInteger() 拒绝所有非正整数值。查看 schema 的调用方有理由相信小数是合法的,但运行时又会拒绝。不是运行时 bug,但确实是 schema 契约层面的真实不一致。

方向:对齐。schema 准确性对工具调用方很重要,把声明类型和执行类型对齐是正确且直接的修复。无需 CHANGELOG 引用——这是一个小一致性修复。

规模:2 行生产代码变更(number → integer,两处),11 行测试代码。不涉及规模阈值。

方案:范围完全正确——两处类型变更加一个聚焦的测试断言防止回归。没有顺手改动,没有范围蔓延。这就是最小修复该有的样子。

进入代码审查 🔍

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Code Review (2a)

Independent proposal: To fix schema/validator mismatch for monitor tool parameters, I would change type: 'number' to type: 'integer' in the schema declaration for both max_events and idle_timeout_ms in monitor.ts, and add a test that asserts the schema type matches the runtime validation contract.

Comparison with PR: The PR's approach matches exactly — two type changes in the schema plus a focused describe('schema') test block. No simpler path was missed.

Correctness: Clean. The schema parametersJsonSchema is the standard mechanism used across the codebase (79 references). The type: 'integer' pattern is already established (89+ occurrences in core). The runtime validator at monitor.ts:737-758 uses Number.isInteger() and remains untouched. The TypeScript interface (MonitorToolParams) correctly keeps number since TypeScript has no integer type — no mismatch there.

Downstream impact: None. The only consumers of max_events/idle_timeout_ms schema are within the monitor tool itself. LLM providers that receive the schema already handle integer types (used throughout the codebase for similar discrete-value parameters).

Reuse check: N/A — this is a metadata fix, not new logic.

No blockers found.

Test Results (2b)

Before (baseline — main branch, no PR)

 ✓ src/tools/monitor.test.ts (73 tests) 72ms

 Test Files  1 passed (1)
      Tests  73 passed (73)
   Duration  5.36s

After (PR applied)

 ✓ src/tools/monitor.test.ts (74 tests) 70ms

 Test Files  1 passed (1)
      Tests  74 passed (74)
   Duration  5.31s

73 → 74 tests. The new declares monitor limits as integers test passes, and all existing runtime validation tests continue to pass. Build unaffected.

中文说明

代码审查 (2a)

独立方案: 要修复 monitor 工具 schema/校验器的不一致,我会把 monitor.tsmax_eventsidle_timeout_ms 的 schema 声明从 type: 'number' 改为 type: 'integer',并添加一个断言 schema 类型与运行时校验契约一致的测试。

与 PR 对比: PR 方案完全一致——两处类型变更加一个聚焦的 describe('schema') 测试块。没有遗漏更简单的路径。

正确性: 干净。parametersJsonSchema 是整个代码库中使用的标准机制(79 处引用)。type: 'integer' 模式已经建立(core 中 89+ 处使用)。monitor.ts:737-758 的运行时校验使用 Number.isInteger() 且未被修改。TypeScript 接口 MonitorToolParams 正确地保持 number 类型,因为 TypeScript 没有 integer 类型——不存在不匹配。

下游影响: 无。max_events/idle_timeout_ms schema 的唯一消费者仅在 monitor 工具内部。接收 schema 的 LLM 提供者已经能处理 integer 类型(代码库中对类似离散值参数广泛使用)。

复用检查: 不适用——这是元数据修复,不是新逻辑。

未发现阻断性问题。

测试结果 (2b)

修改前(main 分支,无 PR):73 个测试全部通过。
修改后(应用 PR):74 个测试全部通过(新增 1 个 schema 断言测试)。

所有现有运行时校验测试继续通过。构建不受影响。

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

qwen-code-ci-bot commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Updated after the author's follow-up commit (cb25bdba): added fractional-value test coverage for max_events: 1.5 and idle_timeout_ms: 500.5, directly addressing the review suggestion about testing Number.isInteger() enforcement through the validator path.

Assessment unchanged from the prior run — the production change is two literal string swaps (numberinteger), the runtime validator is untouched, and the schema now honestly describes what the validator already enforced. The test suite grew from 73 → 74 + 2 new fractional assertions, all passing.

Open suggestion (non-blocking): docs/developers/tools/monitor.md still describes these fields as (number, optional) — worth a follow-up to say (integer, optional) for consistency, but not worth holding this PR for.

Verdict: approve. ✅

中文说明

作者在后续 commit (cb25bdba) 中补充了 max_events: 1.5idle_timeout_ms: 500.5 的小数测试覆盖,直接回应了 review 中关于通过 validator 路径测试 Number.isInteger() 的建议。

评估和上次一致——生产代码变更是两处字符串替换(numberinteger),运行时校验未被修改,schema 现在准确描述了 validator 已经执行的契约。测试套件从 73 → 74 + 2 个小数断言,全部通过。

未解决的建议(不阻断):docs/developers/tools/monitor.md 仍把这些字段描述为 (number, optional)——建议后续更新为 (integer, optional) 以保持一致,但不值得为此等待此 PR。

结论:批准。✅

Qwen Code · qwen3.7-max

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, looks ready to ship. ✅

}
).createInvocation(params);

describe('schema', () => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] The new schema test asserts the static type string, but the existing validation tests (negative, zero, over-limit) never cover fractional/float values like 1.5. The Number.isInteger() rejection path at monitor.ts:740,752 has no test.

Consider adding fractional rejection tests alongside the existing validation tests:

it('rejects fractional max_events', () => {
  expect(validate({ command: 'tail -f log', max_events: 1.5 })).toBe(
    'max_events must be a positive integer.',
  );
});
it('rejects fractional idle_timeout_ms', () => {
  expect(validate({ command: 'tail -f log', idle_timeout_ms: 500.5 })).toBe(
    'idle_timeout_ms must be a positive integer.',
  );
});

— qwen3.7-max via Qwen Code /review

},
max_events: {
type: 'number',
type: 'integer',

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] After this change, AJV enforces type: 'integer' at the schema level, making the manual Number.isInteger() checks at lines 740/752 redundant for the normal code path. However, the schema declares no minimum/maximum, so the manual range checks remain load-bearing. There's no comment explaining which validation layer owns which constraint.

Other tools in the codebase document this explicitly (e.g., shell.test.ts has "Non-number timeout (schema validation catches this first)"). A brief comment at the top of validateToolParamValues would help future maintainers:

// AJV enforces type: 'integer' from the schema. This method adds
// range checks (min/max) that the schema does not express.

— qwen3.7-max via Qwen Code /review

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] The documentation at docs/developers/tools/monitor.md (lines 24, 27) still describes both max_events and idle_timeout_ms as (number, optional). Since this PR tightens the schema to integer, the docs should be updated to (integer, optional) for consistency.

— qwen3.7-max via Qwen Code /review

});

it('rejects fractional max_events', () => {
expect(validate({ command: 'tail -f log', max_events: 1.5 })).toBe(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] The new fractional-rejection tests (and the schema assertion test above) call validateToolParamValues directly via the private-access helper, bypassing AJV schema validation. In production, validateToolParams runs AJV first — which now rejects fractional values at the schema layer before the custom validator ever runs.

Consider adding at least one integration-level test that exercises the full validateToolParams chain with a fractional input, e.g.:

it('rejects fractional max_events via schema validation', () => {
  const result = monitorTool.validateToolParams({
    command: 'tail -f log',
    max_events: 1.5,
  });
  expect(result).not.toBeNull();
});

This would confirm that AJV actually enforces type: 'integer' end-to-end, making the schema change observable in tests.

— qwen3.7-max via Qwen Code /review

@wenshao

wenshao commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, looks ready to ship. ✅

@wenshao
wenshao added this pull request to the merge queue Jul 7, 2026
Merged via the queue into QwenLM:main with commit 46bbe76 Jul 7, 2026
42 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants