#2066 asked for input_examples on the top ~20 tools by call volume. The binding constraint turned out to be budget, not writing: after #2089 reclaimed 3 763 tokens, its own policy required ratcheting the tools/list ceiling down with it, so the real headroom was 317 tokens. Ten examples across five tools cost 199, leaving ~118. The ceiling is not raised. Tools picked from 30 days of mcp.tool_called crossed with the combinations the descriptions already warn about and callers still get wrong: account_override without an explicit vat_treatment (books gross, no moms line), representation without deltagare and syfte, confirmed on a high-risk approval, a balanced voucher where the moms leg is its own line, and get_kpi_report, where one caller sent `metric` 604 times over seven days to a tool whose only parameter is period_id. Examples are also surfaced in the unknown-parameter error. That costs nothing in tools/list, because it only ships on the response to a call that already failed, and it reaches the caller that most needs it: a key list told DueCue's agent which parameter was wrong but not what a correct call looks like, and the same rejected call repeated for a week. Every example is validated against its own schema by the same findUnknownArgKeys guard the server runs, plus required/type/enum/pattern checks. An example our own boundary would reject is worse than none: it teaches the exact mistake the guard then punishes. That test caught three invented enum values in this change's own first draft. Claude-Session: https://claude.ai/code/session_01L3P2hr19PhQuCoTSGoegcY Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
49 lines
2.1 KiB
TypeScript
49 lines
2.1 KiB
TypeScript
/**
|
|
* Top-level argument allow-listing for tools/call.
|
|
*
|
|
* Every tool inputSchema declares `additionalProperties: false` (guarded by
|
|
* strict-schemas.test.ts), but hosts do not reliably enforce it, so a
|
|
* misspelled parameter used to be dropped silently: gnubok_query_journal
|
|
* called with {query} instead of {text} returned the whole journal with
|
|
* applied_filters.text null (feedback seq 261545). Unknown top-level keys are
|
|
* a caller error, never data, and are rejected before execute().
|
|
*
|
|
* company_id is tolerated everywhere: the company-routing layer strips it for
|
|
* company-dependent tools, and a client that always sends it must not break
|
|
* on the few tools that ignore it.
|
|
*/
|
|
export function listArgKeys(inputSchema: Record<string, unknown>): string[] {
|
|
const properties = inputSchema.properties
|
|
if (!properties || typeof properties !== 'object') return []
|
|
return Object.keys(properties as Record<string, unknown>)
|
|
}
|
|
|
|
export function findUnknownArgKeys(
|
|
inputSchema: Record<string, unknown>,
|
|
args: Record<string, unknown>,
|
|
): string[] {
|
|
if (inputSchema.additionalProperties !== false) return []
|
|
const allowed = new Set(listArgKeys(inputSchema))
|
|
return Object.keys(args).filter((key) => key !== 'company_id' && !allowed.has(key))
|
|
}
|
|
|
|
/**
|
|
* The shortest worked example a tool publishes, serialized for an error
|
|
* message, or '' when it has none or the shortest is too long to help.
|
|
*
|
|
* "Valid parameters: period_id" told DueCue's agent which key was wrong but
|
|
* not what a correct call looks like, and the same rejected call repeated for
|
|
* seven days (604 of them). One example costs nothing in tools/list, because
|
|
* it only ships on the response to a call that already failed.
|
|
*/
|
|
export function shortestExampleFor(inputSchema: Record<string, unknown>, maxChars = 200): string {
|
|
const examples = inputSchema.examples
|
|
if (!Array.isArray(examples) || examples.length === 0) return ''
|
|
const serialized = examples
|
|
.map((e) => JSON.stringify(e))
|
|
.filter((json): json is string => typeof json === 'string')
|
|
.sort((a, b) => a.length - b.length)
|
|
const shortest = serialized.find((json) => json.length <= maxChars)
|
|
return shortest ?? ''
|
|
}
|