Skip to content

agents: contract 0.2.0 — generate the tool surface from vendored descriptors#70

Open
ShawnChen-Sirius wants to merge 2 commits into
chdb-io:mainfrom
ShawnChen-Sirius:feat/agents-gate-g2
Open

agents: contract 0.2.0 — generate the tool surface from vendored descriptors#70
ShawnChen-Sirius wants to merge 2 commits into
chdb-io:mainfrom
ShawnChen-Sirius:feat/agents-gate-g2

Conversation

@ShawnChen-Sirius

@ShawnChen-Sirius ShawnChen-Sirius commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

What

TypeScript half of chdb-io/chdb#602 (agents contract 0.2.0). descriptors.json — vendored byte-identical from the Python reference (chdb/agents/descriptors.json) — becomes the single source of the model-visible tool surface:

  • new integrations/agents/descriptors.mjs: CONTRACT_VERSION, loadDescriptors(), toolSpecs(dialect = 'anthropic' | 'openai' | 'mcp'), capabilities(); ChDBTool#toolSpecs(dialect) delegates to it.
  • framework.mjs's AGENT_TOOL_DESCRIPTORS (the zod schema list the Vercel AI SDK and Mastra adapters consume) is now generated mechanically from the same file; the hand-written descriptor list is gone. The adapters themselves are untouched — the descriptor shape ({name, id, description, schema}) is unchanged.
  • capabilities() returns {contract_version, tools, features} for downstream feature-probing (features.dataframe_query is false here — that capability is Python-only).

Drift fixes against the Python reference (behavior changes)

  • A non-numeric maxRows/limit (per-call or constructor) throws a typed ChDBError with type: 'INVALID_ARGUMENT'. Previously Number('lots') produced NaN, every NaN comparison is false, and the row cap was silently disabled — the Python reference raises.
  • maxBytes counts UTF-8 bytes of each row's compact JSON (Buffer.byteLength). String.length counted UTF-16 code units, putting the truncation point up to ~3× later than the reference on non-ASCII rows — a model-visible split between bindings.
  • An explicit empty-string database is rejected like the reference. The previous falsy check treated '' as "no database" and silently dropped the qualifier.
  • On the model-facing call() envelope path, a JSON null optional argument means "omitted" (matches the reference).

Conformance fixture

integrations/agents/conformance/ re-synced with upstream: the fixture now starts with a header record whose contract_version the runner asserts against this binding's CONTRACT_VERSION (a stale vendored fixture fails loudly), and cases may carry "requires": "<feature>" — the runner skips them when capabilities() lacks the feature (this is how the Python-only dataframe_query case is handled here). New cases cover every behavior above. CONTRACT.md mirror re-synced.

Tests

npx vitest run test/v3/integrations/63 passed (21 conformance cases, 12 agents unit tests incl. dialect rendering, descriptors/zod parity, capabilities, argument validation; ai-sdk/mastra/hypequery suites unaffected).

🤖 Generated with Claude Code

Note

Generate agents tool surface from vendored descriptors in contract 0.2.0

  • Introduces descriptors.json as the single source of truth for the model-visible tool surface, replacing hard-coded definitions in framework.mjs and tool.mjs.
  • Adds loadDescriptors(), toolSpecs(dialect), and capabilities() functions in descriptors.mjs, supporting 'anthropic', 'openai', and 'mcp' dialects; unknown dialects throw a typed INVALID_ARGUMENT error.
  • Adds intArg() validation to ChDBTool constructor and call-site caps (maxRows, maxBytes, maxExecutionTime); non-numeric values now throw typed INVALID_ARGUMENT errors instead of silently coercing to NaN.
  • ChDBTool.call() now returns an error envelope for non-object arguments (including arrays and JSON null) rather than proceeding or throwing.
  • Conformance suite in cases.jsonl gains a header record with contract_version and feature-gated cases driven by capabilities().features.
  • Behavioral Change: truncation in query() now measures UTF-8 bytes via Buffer.byteLength(JSON.stringify(row), 'utf8') instead of string length, which changes truncation boundaries for non-ASCII data.

Macroscope summarized 8e5d77d.

…riptors

descriptors.json (vendored byte-identical from the Python reference in
chdb-io/chdb) becomes the single source of the model-visible tool surface:

- new descriptors.mjs: CONTRACT_VERSION, loadDescriptors(),
  toolSpecs(dialect='anthropic'|'openai'|'mcp'), capabilities();
  ChDBTool#toolSpecs(dialect) delegates to it.
- framework.mjs AGENT_TOOL_DESCRIPTORS (the zod schemas the Vercel AI SDK /
  Mastra adapters consume) is now generated mechanically from the same file;
  the hand-written descriptor list is gone.

Drift fixes against the Python reference, now conformance-tested:

- a non-numeric maxRows/limit throws ChDBError(INVALID_ARGUMENT); previously
  Number(...) produced NaN, every NaN comparison is false, and the row cap
  was silently disabled.
- maxBytes counts UTF-8 bytes of each row's compact JSON (Buffer.byteLength);
  String.length counted UTF-16 units, putting the truncation point up to ~3x
  later than the reference on non-ASCII rows.
- an explicit empty-string database is rejected like the reference; the falsy
  check treated '' as "no database" and silently dropped the qualifier.

conformance fixture re-synced (header record with contract_version,
capability gating, new cases); CONTRACT.md mirror re-synced.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ShawnChen-Sirius

Copy link
Copy Markdown
Contributor Author

@chibugai, review it

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Aligns the TypeScript agents binding with agents contract 0.2.0 by making the vendored descriptors.json the single source of truth for the model-visible tool surface, and updating the framework adapters + conformance fixtures/tests to be generated/validated from it.

Changes:

  • Added integrations/agents/descriptors.mjs (+ typings + vendored descriptors.json) to generate tool specs for multiple dialects and expose capabilities()/CONTRACT_VERSION.
  • Updated ChDBTool and the framework adapter surface to consume generated tool specs and to match Python-reference drift fixes (typed INVALID_ARGUMENT for non-numeric caps, UTF-8 byte counting for maxBytes, reject empty-string database qualifier).
  • Re-synced and strengthened the conformance fixture/test runner to assert contract version headers and capability-gate optional cases.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
test/v3/integrations/agents-tool.test.ts Adds unit coverage for descriptor-generated tool surfaces, capabilities, and argument validation.
test/v3/integrations/agents-conformance.test.ts Updates conformance runner to handle fixture header records and capability-gated cases.
integrations/agents/tool.mjs Implements contract 0.2.0 drift fixes; delegates tool spec generation to descriptors module.
integrations/agents/tool.d.mts Updates TS declarations for the new toolSpecs(dialect) signature.
integrations/agents/index.mjs Re-exports descriptors/capabilities APIs from the agents entrypoint.
integrations/agents/index.d.mts Re-exports new descriptors types and functions in typings.
integrations/agents/framework.mjs Generates AGENT_TOOL_DESCRIPTORS mechanically from descriptors.json via loadDescriptors().
integrations/agents/descriptors.mjs New generator for dialect tool specs + capabilities surface + contract version constant.
integrations/agents/descriptors.json Vendored, contract-governed tool descriptor source of truth (contract 0.2.0).
integrations/agents/descriptors.d.mts Adds typings for descriptors module public API.
integrations/agents/CONTRACT.md Updates contract mirror with descriptors.json + capabilities/versioning details and new normative notes.
integrations/agents/conformance/README.md Updates fixture documentation to include header record + capability gating.
integrations/agents/conformance/cases.jsonl Adds header record, new drift-fix cases, and capability-gated optional case(s).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread test/v3/integrations/agents-conformance.test.ts Outdated
Comment thread integrations/agents/descriptors.mjs
Comment thread integrations/agents/framework.mjs Outdated
Review follow-ups on the contract-0.2.0 change, mirroring the Python
reference:

- loadDescriptors() returns a structuredClone of the cached parse, so a caller
  mutating the result can no longer corrupt what toolSpecs()/capabilities()/
  AGENT_TOOL_DESCRIPTORS generate for everyone else in-process; a
  missing/broken descriptors.json now throws a diagnosable ChDBError instead
  of a raw fs error or SyntaxError.
- An unknown param type in descriptors.json fails loudly in both renderings
  (jsonSchema and the zod codegen) instead of falling through to a permissive
  z.record — a typo in the shared asset must not silently degrade the
  model-visible argument schema.
- call() validates the arguments payload before dispatch: a non-object
  (string/number/array) returns the {ok: false, INVALID_ARGUMENT} envelope.
  Previously a string would spread into {0: 'S', 1: 'E', ...} garbage and run
  anyway, while the Python reference raised — both bindings now return the
  same envelope (new conformance case p4_malformed_arguments).
- The conformance runner enforces the fixture shape: the first record must be
  the header, every later record must carry an "id" — a case that lost its id
  fails the run instead of being silently reclassified as a second header.

Tests: 66 passed (was 63).

Co-Authored-By: Claude Fable 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.

3 participants