fix: resolve 25 pre-publish blockers
- postinstall.mjs: fix alias package detection - migrate-legacy-plugin-entry: dedupe + regression tests - task_system: default consistency across runtime paths - task() contract: consistent tool behavior - runtime model selection, tool cap, stale-task cancellation - recovery sanitization, context-limit gating - Ralph semantic DONE hardening, Atlas fallback persistence - native-skill description/content, skill path traversal guard - publish workflow: platform awaited via reusable workflow job - release: version edits reapplied before commit/tag - JSONC plugin migration: top-level plugin key safety - cold-cache: user fallback models skip disconnected providers - docs/version/release framing updates Verified: bun test (4599 pass), tsc --noEmit clean, bun run build clean
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
const { describe, expect, test } = require("bun:test")
|
||||
const { createToolExecuteBeforeHandler } = require("./tool-execute-before")
|
||||
const { createToolRegistry } = require("./tool-registry")
|
||||
const { builtinTools } = require("../tools")
|
||||
|
||||
describe("createToolExecuteBeforeHandler", () => {
|
||||
test("does not execute subagent question blocker hook for question tool", async () => {
|
||||
@@ -268,6 +269,44 @@ describe("createToolRegistry", () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#given max_tools is lower than or equal to builtin tool count", () => {
|
||||
describe("#when creating the tool registry", () => {
|
||||
test("#then it trims to the exact configured cap", () => {
|
||||
const result = createToolRegistry(
|
||||
createRegistryInput({
|
||||
experimental: { max_tools: Object.keys(builtinTools).length },
|
||||
}),
|
||||
)
|
||||
|
||||
expect(Object.keys(result.filteredTools)).toHaveLength(Object.keys(builtinTools).length)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#given max_tools is set below the full plugin tool count", () => {
|
||||
describe("#when creating the tool registry", () => {
|
||||
test("#then it enforces the exact cap deterministically", () => {
|
||||
const result = createToolRegistry(
|
||||
createRegistryInput({
|
||||
experimental: { max_tools: 10 },
|
||||
}),
|
||||
)
|
||||
|
||||
expect(Object.keys(result.filteredTools)).toHaveLength(10)
|
||||
})
|
||||
|
||||
test("#then it keeps the task tool when lower-priority tools can satisfy the cap", () => {
|
||||
const result = createToolRegistry(
|
||||
createRegistryInput({
|
||||
experimental: { max_tools: 10 },
|
||||
}),
|
||||
)
|
||||
|
||||
expect(result.filteredTools.task).toBeDefined()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
export {}
|
||||
|
||||
+58
-23
@@ -40,6 +40,63 @@ export type ToolRegistryResult = {
|
||||
taskSystemEnabled: boolean
|
||||
}
|
||||
|
||||
const LOW_PRIORITY_TOOL_ORDER = [
|
||||
"session_list",
|
||||
"session_read",
|
||||
"session_search",
|
||||
"session_info",
|
||||
"interactive_bash",
|
||||
"look_at",
|
||||
"call_omo_agent",
|
||||
"task_create",
|
||||
"task_get",
|
||||
"task_list",
|
||||
"task_update",
|
||||
"background_output",
|
||||
"background_cancel",
|
||||
"hashline_edit",
|
||||
"ast_grep_replace",
|
||||
"ast_grep_search",
|
||||
"glob",
|
||||
"grep",
|
||||
"skill_mcp",
|
||||
"skill",
|
||||
"task",
|
||||
"lsp_rename",
|
||||
"lsp_prepare_rename",
|
||||
"lsp_find_references",
|
||||
"lsp_goto_definition",
|
||||
"lsp_symbols",
|
||||
"lsp_diagnostics",
|
||||
] as const
|
||||
|
||||
function trimToolsToCap(filteredTools: ToolsRecord, maxTools: number): void {
|
||||
const toolNames = Object.keys(filteredTools)
|
||||
if (toolNames.length <= maxTools) return
|
||||
|
||||
const removableToolNames = [
|
||||
...LOW_PRIORITY_TOOL_ORDER.filter((toolName) => toolNames.includes(toolName)),
|
||||
...toolNames
|
||||
.filter((toolName) => !LOW_PRIORITY_TOOL_ORDER.includes(toolName as (typeof LOW_PRIORITY_TOOL_ORDER)[number]))
|
||||
.sort(),
|
||||
]
|
||||
|
||||
let currentCount = toolNames.length
|
||||
let removed = 0
|
||||
|
||||
for (const toolName of removableToolNames) {
|
||||
if (currentCount <= maxTools) break
|
||||
if (!filteredTools[toolName]) continue
|
||||
delete filteredTools[toolName]
|
||||
currentCount -= 1
|
||||
removed += 1
|
||||
}
|
||||
|
||||
log(
|
||||
`[tool-registry] Trimmed ${removed} tools to satisfy max_tools=${maxTools}. Final plugin tool count=${currentCount}.`,
|
||||
)
|
||||
}
|
||||
|
||||
export function createToolRegistry(args: {
|
||||
ctx: PluginContext
|
||||
pluginConfig: OhMyOpenCodeConfig
|
||||
@@ -158,29 +215,7 @@ export function createToolRegistry(args: {
|
||||
|
||||
const maxTools = pluginConfig.experimental?.max_tools
|
||||
if (maxTools) {
|
||||
const estimatedBuiltinTools = 20
|
||||
const pluginToolBudget = maxTools - estimatedBuiltinTools
|
||||
const toolEntries = Object.entries(filteredTools)
|
||||
if (pluginToolBudget > 0 && toolEntries.length > pluginToolBudget) {
|
||||
const excess = toolEntries.length - pluginToolBudget
|
||||
log(`[tool-registry] Tool count (${toolEntries.length} plugin + ~${estimatedBuiltinTools} builtin = ~${toolEntries.length + estimatedBuiltinTools}) exceeds max_tools=${maxTools}. Trimming ${excess} lower-priority tools.`)
|
||||
const lowPriorityTools = [
|
||||
"session_list", "session_read", "session_search", "session_info",
|
||||
"call_omo_agent", "interactive_bash", "look_at",
|
||||
"task_create", "task_get", "task_list", "task_update",
|
||||
]
|
||||
let removed = 0
|
||||
for (const toolName of lowPriorityTools) {
|
||||
if (removed >= excess) break
|
||||
if (filteredTools[toolName]) {
|
||||
delete filteredTools[toolName]
|
||||
removed += 1
|
||||
}
|
||||
}
|
||||
if (removed < excess) {
|
||||
log(`[tool-registry] WARNING: Could not trim enough tools. ${toolEntries.length - removed} plugin tools remain.`)
|
||||
}
|
||||
}
|
||||
trimToolsToCap(filteredTools, maxTools)
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user