Skip to content

feat(validate): warn on tool parameters without descriptions - #156

Merged
Asaf-prog merged 1 commit into
extra-org:mainfrom
Rsakhuja:feat/114-tool-param-description-warnings
Nov 1, 2026
Merged

Asaf-prog merged 1 commit into
extra-org:mainfrom
Rsakhuja:feat/114-tool-param-description-warnings

Conversation

@Rsakhuja

@Rsakhuja Rsakhuja commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

First, non-breaking step toward #114.

Changes

  • agent_engine/core/tool_metadata.py (new): statically scans each declared tool in plugins/tools/<id>.py (parsed with ast, never imported, same approach as plugin_stubs) and reports parameters whose description is missing or blank. *args/**kwargs are skipped; missing or unparseable files are left to the existing checks.
  • agentctl validate: ValidationResult gains warnings. They are printed but never fail validation:
    warnings:
      ! tool "get_customer": parameter "customer_code" is missing a description
    ✓ validation passed
    
    SystemSpecValidator is unchanged, so serve/chat startup is unaffected.
  • plugin_stubs.find_function: made public for reuse (rename only).
  • Docs: Annotated example in mcp-and-tools.mdx / MCP_AND_TOOLS.md, a note in cli.mdx, and a correction: mcp-and-tools.mdx said the docstring becomes the tool description the LLM sees, but the engine always sends the YAML description.

Tool parameters reach the LLM as the tool's input schema. Descriptions
written as `Annotated[T, "..."]` are already copied into that schema by
StructuredTool.from_function, but nothing checked that they exist, so the
model is often left to guess what value a parameter expects.

`agentctl validate` now statically scans each declared tool (ast, no
import) and reports parameters with a missing or blank description as
warnings. Warnings never fail validation and are not part of
SystemSpecValidator, so serve/chat startup is unaffected: every shipped
example tool would otherwise fail today.

Also correct docs/mcp-and-tools.mdx, which said the docstring becomes the
tool description the LLM sees; the engine always sends the YAML
description.

First step of extra-org#114.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mintlify

mintlify Bot commented Nov 1, 2026

Copy link
Copy Markdown

Preview approval required

This pull request comes from a fork, so Mintlify won't build a preview until someone with write access approves commit 43b875a.

Approve preview

@Asaf-prog

Copy link
Copy Markdown
Collaborator

Thanks for the contribution. This looks like a useful, focused first step toward #114. I reviewed commit 43b875a: make check passed locally with 1,586 tests passing, and make validate passed for both examples. I found no blocking issues.

One non-blocking follow-up in src/agent_engine/core/tool_metadata.py:65–70: the scanner currently warns about runtime-only parameters that LangChain excludes from the model-facing tool schema.

For example, a tool with a described query parameter and config: RunnableConfig produces:

tool "lookup": parameter "config" is missing a description

However, its tool_call_schema exposes only query to the model.

It would be good to exclude these internal parameters from the description check and add a regression test, especially before promoting these warnings to errors. This can be handled in a follow-up PR and does not block this one.

@Asaf-prog
Asaf-prog merged commit 53724f4 into extra-org:main Nov 1, 2026
3 checks passed
Asaf-prog pushed a commit that referenced this pull request Nov 2, 2026
The parameter-description check warned about parameters LangChain fills
in at runtime and leaves out of the model-facing tool schema, e.g.
`config: RunnableConfig` produced "parameter "config" is missing a
description" although `tool_call_schema` exposes only the other params.

Skip them in the static scan, mirroring langchain_core's filtering:
`callbacks`/`run_manager` by name, a bare `RunnableConfig` (an optional
one is still shown to the model), `ToolRuntime`, and `Annotated[...]`
with an `Injected*` marker (InjectedToolArg, InjectedToolCallId,
LangGraph InjectedState/InjectedStore). Matching is by name, since the
scan never imports tool code.

Follow-up to #156 review; step toward #114.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

2 participants