feat(tool-web): declare web tool timeout budgets via config

fetchTimeoutMs/searchTimeoutMs (default 30000) resolve to each tool's
ToolDefinition.timeoutMs, moving the budget's declaration home onto the
owning tool plugin and preserving per-tool deployment override without a
mistypable central tool-name map.
This commit is contained in:
Dudu-0223
2026-07-08 14:40:14 +08:00
parent 534b1dc6d0
commit 7a822ee402
6 changed files with 74 additions and 17 deletions
@@ -349,3 +349,31 @@ describe('searchMaxResults is plugin config', () => {
.rejects.toThrow(/tool-web: searchMaxResults must be a positive integer/)
})
})
describe('tool-call timeout budget is plugin config', () => {
it('attaches the default 30s budget to web_fetch and web_search', async () => {
const { fiber, ctx } = await mountTools()
expect(ctx.tools.get('web_fetch')?.timeoutMs).toBe(30_000)
expect(ctx.tools.get('web_search')?.timeoutMs).toBe(30_000)
await fiber.dispose()
})
it('honors per-tool timeout overrides from config', async () => {
const { fiber, ctx } = await mountTools({ config: { fetchTimeoutMs: 60_000, searchTimeoutMs: 10_000 } })
expect(ctx.tools.get('web_fetch')?.timeoutMs).toBe(60_000)
expect(ctx.tools.get('web_search')?.timeoutMs).toBe(10_000)
await fiber.dispose()
})
it.each([
['fetchTimeoutMs', { fetchTimeoutMs: 0 }],
['searchTimeoutMs', { searchTimeoutMs: -5 }],
])('rejects a non-positive-integer %s at load', async (key, config) => {
const ctx = new Context()
await ctx.plugin(SystemPrompt)
await ctx.plugin(ToolRegistry)
await ctx.plugin(WebService, {})
await expect(ctx.plugin(ToolWeb, config))
.rejects.toThrow(new RegExp(`tool-web: ${key} must be a positive integer`))
})
})