Conversation
New @graphql-hive/semantic-introspection workspace package — TypeScript port of HotChocolate's semantic introspection (ChilliCream). Empty scaffold only: package.json (peer-dep graphql, dual ESM/CJS via pkgroll), README crediting the reference implementation, CHANGELOG seed, and an index.ts stub. Public surface fills in across the next sub-tasks.
Add `applySemanticIntrospection(schema, opts) → schema`, the public entry
point that extends a host schema with the `__SearchResult` type, the
`__SchemaDefinition` union, and the two Query fields `__search` and
`__definitions`. SDL matches HotChocolate's SemanticIntrospectionSchema.cs
verbatim. The host query type does not have to be literally named Query.
Also introduces the leaf-only `SchemaSearchProvider` interface (two
methods: search → {coordinate, score, cursor}[], plus getPathsToRoot
resolved separately) that P3.4 will satisfy with a BM25 default.
Stub resolvers return empty results; P3.3 wires them to a real provider.
Uses `assumeValid: true` on extendSchema to opt into the introspection-
namespace names the RFC requires.
9 tests cover schema additions, original-field preservation, custom query
type names, schema immutability, the no-query-type error path, and
standard `__schema` introspection passing through unmodified.
Port HotChocolate's BM25 search provider into TypeScript: - `Bm25Document`: schema-coordinate-keyed indexable doc. - `tokenize`: camelCase / PascalCase / acronym + non-alphanumeric splitting; single-character tokens filtered; lowercase output. Matches .NET BM25Tokenizer behavior (including digit-letter transitions NOT triggering splits). - `Bm25Index`: inverted index with BM25 scoring (K1=1.2, B=0.75). Standard IDF formula `ln((N-df+0.5)/(df+0.5)+1)`; sorted by score descending. - `indexSchema`: walks GraphQLSchema, emits documents for types/fields-on-complex-types/enum values/input-object fields with text = `name + " " + description`; skips `__*` introspection (including our own meta-types) and does NOT index directives. Adds `excludeDeprecated` as an additive enhancement over the .NET reference, filtering @deprecated content from the agent-facing surface only (underlying schema unaffected). - `Bm25SearchProvider`: implements `SchemaSearchProvider` with cursor pagination (little-endian int32 base64, interop with .NET), minScore filtering, normalized scores in `[0, 1]`, and BFS getPathsToRoot capped at 5 paths shortest-first. `SearchQueryTooLargeError` + `InvalidSearchCursorError`. Public exports added: `Bm25SearchProvider`, `Bm25SearchProviderOptions`, and the two error classes. 40 new unit tests across tokenizer / bm25-index / schema-indexer / bm25-search-provider; full package suite is 49 tests green, typecheck and prettier clean.
Replace P3.2's stub resolvers with real wiring against a SchemaSearchProvider. By default applySemanticIntrospection now constructs a Bm25SearchProvider over the extended schema; a custom provider can be supplied via options.provider. The excludeDeprecated flag is forwarded to the default provider; if a custom provider is supplied, the flag is ignored (the provider owns its own filter policy). New `resolvers.ts` exports: - `lookupCoordinate(schema, coordinate)` — resolves `TypeName`, `TypeName.member`, and `@directiveName` coordinates to the corresponding graphql-js runtime object. - `resolveSchemaDefinitionType(value)` — distinguishes the five __SchemaDefinition union members via graphql-js's type guards (isNamedType / isDirective) plus duck-typing for Field / EnumValue / InputValue (which graphql-js doesn't class-tag). apply.ts wires: - Query.__search → provider.search(query, first, after, minScore). - Query.__definitions → coordinate-by-coordinate lookup (unknown coords are silently omitted from the result list). - __SearchResult.definition → lookupCoordinate(coordinate). - __SearchResult.pathsToRoot → provider.getPathsToRoot(coordinate). - __SchemaDefinition.__resolveType → resolveSchemaDefinitionType. Note: deprecated-member filtering and empty-after-filter type OMISSION in __definitions are intentionally deferred to P3.5 — this commit is wiring, P3.5 layers the policy on top. 10 new end-to-end tests cover all five union members, default and custom providers, pathsToRoot resolution, and unknown-coordinate skipping. Full suite at 57 tests green, typecheck and prettier clean.
…tions omission Adds the public utility detectEmptyAfterFilter(schema, opts) that classifies which types would be left empty by an agent-facing filter (currently: @deprecated). Transitive fixed-point covering all Kinds: - Object / Interface: zero non-deprecated fields → empty. - Input object: zero non-deprecated fields → empty. - Enum: zero non-deprecated values → empty. - Union: zero non-empty members → empty (recursive). - Scalar: never empty. Wires the detector into __definitions / __SearchResult.definition via the new `filteredLookup` helper in resolvers.ts: - @deprecated members (field / enum value / input field) are omitted from results when excludeDeprecated is set. - empty-after-filter types are omitted entirely from __definitions (emitting `__Type` with `fields: []` would violate the introspection validity contract — buildClientSchema rejects it). Non-cascade per the locked design: a non-deprecated field whose return type is empty-after-filter stays visible — the agent sees an opaque return type rather than the field disappearing. The detection utility is exported so a downstream ACL package can implement its own delete-or-cascade policy at SDL-rewrite time. Standard __schema / __type introspection remains unchanged — it always returns the full underlying schema (including @deprecated content). Public exports added: `detectEmptyAfterFilter`, `DetectEmptyAfterFilterOptions`, `DetectEmptyAfterFilterResult`, `EmptyReason`. 15 new tests across detect-empty-after-filter spec + apply spec (omission, deprecated member skip, non-cascade reference case, standard introspection passthrough). Full suite is 72 tests green, typecheck and prettier clean.
…matrix Two new spec files round out the integration coverage: conformance.spec.ts — runs the EXACT __search and __definitions query shapes from Pascal Senn's apidays-singapore skill prompt (case-study/prompt-graphql-skill.md). Verifies our wire shapes interoperate with what real agents send today: nested type/ofType expansion for NonNull/List wrappers, args.type.ofType.kind, enumValues on __Type, field-alias `fieldName: name`, and the full __SchemaDefinition union typename surface. fixture-matrix.spec.ts — single kitchen-sink schema exercising empty-after-filter omission across all Kinds (Object / Input / Enum / Interface / Union with mixed survivors / Union with all-empty members), the deprecated-member skip across the same matrix, and the non-cascade guarantees (a non-deprecated field whose RETURN type or ARG type is empty-after-filter stays visible — the agent gets an opaque type rather than the field disappearing). Also reasserts that standard __schema / __type introspection passes the full underlying schema through unmodified. 14 new tests; full suite is 86 green, typecheck and prettier clean.
README expanded from the in-development skeleton to a full reference: quick-start usage, the exact SDL the package adds to a host schema, the full options surface, deprecated-field handling semantics and their non-cascade guarantees, the pluggable SchemaSearchProvider API, and the detectEmptyAfterFilter utility for downstream tools. Changeset: minor bump for the new package (0.0.0 → 0.1.0). Description credits ChilliCream / Pascal Senn as the reference implementation and calls out the additive `excludeDeprecated` flag as the one place we extend beyond the .NET behavior. PR-1 close-out — pkgroll dual CJS/ESM build verified, 86 tests green, typecheck and prettier clean across the whole package.
`lookupCoordinate`, `filteredLookup`, `resolveSchemaDefinitionType`, and their accompanying types (`LookupFilter`, `SchemaDefinitionValue`) are useful primitives for downstream callers that want to integrate semantic-introspection without going through the schema-extension path — e.g. running it inside an MCP tool handler over a federated supergraph, where `applySemanticIntrospection`'s `extendSchema` would clobber `@join__field` directives. No new tests required: the helpers are unchanged; this commit only moves them across the package boundary. Existing 172 tests still pass.
…to-root BFS From an adversarial review pass: - decodeCursor: `Buffer.from(s,'base64')` is lenient (never throws, silently drops invalid chars), so the old try/catch was dead and `InvalidSearchCursorError` (public API) almost never fired — garbage/non-canonical cursors decoded to an arbitrary offset. Now validate canonically: require exactly 4 bytes AND re-encode to confirm the input was the canonical base64 of those bytes. - findPathsToRoot: the BFS dequeued with `queue.shift()` (O(n) per shift → O(V²) overall). Switch to a head cursor for true O(V+E). Invisible at small schema sizes but it's library code that may index large supergraphs. All 172 package tests still pass.
…tream
A standards pass against the hive-gateway monorepo's house conventions
(sampled jwt-auth, mcp, opentelemetry plugins). No behavior changes —
all 172 tests still pass; typecheck and pkgroll build clean.
Highlights:
- Drop project-development meta-commentary from source ("locked Phase 3
design", "for later phases", "for upstream"; references to internal
artifacts e.g. Pascal's apidays-singapore case-study path; "Direct
port of HotChocolate's …" attributions repeated across file headers).
Port attribution lives in the README's existing acknowledgments
section and the changeset, not in source.
- Remove ASCII section-divider comments (`// ── … ──`) in apply.ts;
the single attachResolvers function becomes four focused helpers
(attachSearchResolver, attachDefinitionsResolver,
attachSearchResultResolvers, attachDefinitionUnionResolveType),
mirroring the small-helpers style of registry.ts.
- Drop pervasive `readonly` discipline on interface fields and
constructor params across the BM25 files; the host repo's
comparable types (MCPTool, JsonSchema, RegisteredTool) use plain
fields.
- Collapse custom error classes (SearchQueryTooLargeError,
InvalidSearchCursorError) to plain Error/RangeError with rich
messages, matching how registry.ts surfaces errors. Drop the empty
Bm25SearchProviderOptions interface (forward-compat scaffolding for
hyperparameters that don't exist) — accept SchemaIndexerOptions
directly.
- Convert Bm25Index from `static build()` + private constructor to a
plain public constructor that builds inline (matches ToolRegistry's
pattern). Call sites updated; tests updated to use `new Bm25Index`.
- Trim JSDoc density on internal helpers across resolvers.ts,
detect-empty-after-filter.ts, apply.ts; keep one-line JSDoc on
public symbols only.
- Drop `[@graphql-hive/semantic-introspection]` error-message prefixes
throughout (registry.ts identifies errors by entity name, not
package name).
- Test cleanups: strip editorial parentheticals from `it()` titles
("(non-cascade)", "(default BM25 provider)", "— for later phases"),
remove "Locked design choice" inline comments, replace the
Pascal/apidays describe block with `describe('RFC conformance', …)`,
trim 3- and 4-line comment blocks down to one line where the assertion
already documents the behavior.
…federated graphs Adds a 'Using with MCP' section to the package README. Documents recommended `instructions` field wording for MCP servers exposing `__search` / `__definitions` over a federated graph, with empirical justification from a 12-trial A/B over a federated test deployment: composition-pushing wording produced tightly clustered behavior on natural-language prompts (~11 MCP calls, one composed operation, batched definitions), while a workflow-only baseline averaged fewer calls but admitted a thrash mode (63 calls / 18 separate query ops in 1/4 trials).
…vider JSDoc Attribution belongs in README / changeset per house style, not source file headers. README's 'Reference implementation' section retains the ChilliCream + Pascal Senn credit. JSDoc keeps the path-unaware-ranker design rationale since it's a non-obvious invariant a maintainer might otherwise break by consolidating the two methods.
Review Summary by Qodo(Agentic_describe updated until commit 6ae18ca)Add @graphql-hive/semantic-introspection package with semantic schema discovery
WalkthroughsDescription• Add @graphql-hive/semantic-introspection package with __search and __definitions fields • Implement BM25 search provider with tokenization and ranking algorithm • Support optional excludeDeprecated filter for agent-facing schema surface • Export detectEmptyAfterFilter utility for downstream schema rewriting tools • Include 86 comprehensive unit tests covering RFC conformance and edge cases Diagramflowchart LR
Schema["GraphQL Schema"] -- "applySemanticIntrospection" --> Extended["Extended Schema<br/>with __search & __definitions"]
Extended -- "__search query" --> BM25["BM25SearchProvider<br/>tokenize & rank"]
BM25 -- "SchemaSearchResult[]" --> Results["Ranked Coordinates<br/>with scores & paths"]
Extended -- "__definitions query" --> Lookup["filteredLookup<br/>resolve coordinates"]
Lookup -- "SchemaDefinitionValue" --> Union["__SchemaDefinition Union<br/>__Type | __Field | ..."]
Schema -- "detectEmptyAfterFilter" --> Empty["Empty Types Set<br/>after @deprecated filter"]
File Changes1. packages/semantic-introspection/src/apply.ts
|
Code Review by Qodo
1. Unbounded __search page size
|
Code Review by Qodo
1. Non-null definition can be null
|
There was a problem hiding this comment.
Code Review
This pull request introduces the @graphql-hive/semantic-introspection package, a TypeScript port of HotChocolate's Semantic Introspection that adds __search and __definitions fields to GraphQL schemas for AI agent discovery. It includes a BM25-based search provider, a BFS path-to-root traversal, and a utility to detect empty types after filtering deprecated members. The review feedback highlights a bug in the BFS path-to-root algorithm where a global visited set limits path discovery, and recommends replacing Node.js-specific Buffer usages with standard Web APIs to improve edge runtime portability.
… BFS A single function-scoped `visited` set caused parallel routes to root to be silently dropped: as soon as one path reached `Query`, `Query` entered `visited` and every other path through it (or through any intermediate type seen) was skipped. With the default `maxPaths=5`, typical schemas got at most one path returned regardless. Each BFS queue entry now carries its own visited set, allowing distinct paths to legitimately pass through the same intermediate or root type while still preventing cycles within a single path. The existing "finds multiple paths from a deeply reachable type" test asserted only `>= 1` paths, which the buggy code satisfied; strengthened to compare exact path lists, and added a second case where two root fields return the same type.
… deprecated `@deprecated(reason: "")` is a valid deprecation: graphql-js sets `deprecationReason` to a string whenever the directive is applied, including the empty-string form. Truthiness / length checks across the package mis-classified those members as non-deprecated, leaking them into `__search` and `__definitions` and miscalculating empty-after-filter classification. Standardized on `typeof v.deprecationReason === 'string'` across: - `isDeprecatedMember` in resolvers.ts - three filter sites in the BM25 schema indexer - four surviving-member filters in detectEmptyAfterFilter Regression tests cover the empty-string form for object / interface / input / enum surfaces.
…otect non-null `definition` `__SearchResult.definition` is declared `__SchemaDefinition!` in the SDL, but the default BM25 indexer always indexes the type document — including types that become empty-after-filter under `excludeDeprecated: true`. The resolver then ran `filteredLookup` on those coordinates, returned `null`, and triggered GraphQL non-null propagation that nulled the entire `__search` field. The fix moves the filter to the `__search` resolver itself: after `provider.search(...)`, results whose coordinate fails `filteredLookup` are dropped before the page is returned. The cursor still advances past the dropped raw positions, so pagination remains correct; a page can come back shorter than `first`. This also hardens the contract against custom providers that emit synthetic or stale coordinates — those are now silently dropped rather than crashing the whole field. The previous test "uses a custom provider when one is supplied via options" relied on the bug by returning a coordinate that did not exist in the schema; updated to a real coordinate, and a dedicated test added for the misbehaving-provider case.
…terFilter fast path The `excludeDeprecated: false` branch returned a module-level shared `EMPTY_RESULT` whose `Set` and `Map` are mutable at runtime despite the `Readonly*` interface. Any caller mutating the returned collections would pollute every subsequent call of a public utility. Each call now constructs and returns a fresh empty result; the `EMPTY_RESULT` constant is removed. Regression test mutates the result of one call and verifies the next call is uncontaminated.
… in cursor codec Cursor encode/decode used `Buffer.alloc`, `writeInt32LE`, `Buffer.from`, and `readInt32LE` — Node-only globals that aren't available in Cloudflare Workers, Deno, the browser, or any other runtime hive-gateway intends to support. Swapped to standard Web APIs (`Uint8Array` + `DataView` + `btoa` / `atob`), all available in Node ≥16 and ubiquitous elsewhere. Validation logic is unchanged: `atob` throws on malformed base64 (narrowly caught and rethrown with the same message); byte-length, in-range, and canonical-roundtrip checks remain explicit `if (...) throw` statements rather than being wrapped in a catch-all `try/catch`. Existing cursor tests cover the behavior.
|
/review |
|
Code review by qodo was updated up to the latest commit 84ee76a |
PR Reviewer Guide 🔍Warning
Here are some key observations to aid the review process:
|
…provider page is filtered The resolver-layer filter introduced for the non-null `definition` guarantee could lose pagination entirely: if every coordinate in a provider page failed `filteredLookup`, the resolver returned `[]` with no cursor, and the client had no way to advance to the next provider page — later valid hits became unreachable. The `__search` resolver now loops, fetching successive provider pages until it accumulates `first` survivors or the provider exhausts. A safety guard (`SEARCH_MAX_PROVIDER_PAGES = 16`) plus a non-advancing-cursor check prevent runaway loops against misbehaving providers. Two regression tests: one verifies the loop reaches a real result on a later provider page after a fully-filtered first page; the other confirms the safety guard short-circuits a provider that returns the same cursor forever.
…as `__search` / `__definitions`
`applySemanticIntrospection` uses `extendSchema(..., { assumeValid:
true })` so graphql-js will accept the `__`-prefixed RFC names.
That same flag skips graphql-js's collision detection — applying
the function twice on a schema (or running it against a host that
constructed `__search` / `__definitions` itself via constructor
APIs) would silently produce a duplicate-extension schema instead
of failing.
Added an explicit precondition that inspects the query type's
fields before extending and throws a clean error on collision.
Regression test exercises the double-application case.
…ToRoot BFS The multi-path BFS allocated a fresh `visited` Set on every branch (O(V) copy each), which scales poorly on richly-connected schemas. Replaced with a small `pathRevisits` helper that walks the in-flight path linearly — paths are short in practice (≤ schema depth) and the linear scan is cheaper than the Set construction. Behavior is identical (same cycle-prevention semantics: a type name may not repeat within a single path, but distinct paths may legitimately share intermediate or root types). All existing BFS tests, including the two regressions added in ca2b871, pass unchanged.
|
/agentic_review |
|
Code review by qodo was updated up to the latest commit d4a93be |
1 similar comment
|
Code review by qodo was updated up to the latest commit d4a93be |
| ) => { | ||
| const target = args.first; | ||
| const minScore = args.minScore ?? null; | ||
| const survivors: SchemaSearchResult[] = []; | ||
| let after = args.after ?? null; | ||
|
|
||
| // Loop until we have `first` survivors or the provider is exhausted. | ||
| // A naive single-page fetch would lose pagination entirely when a | ||
| // whole page is filtered out: the client gets `[]` with no cursor | ||
| // and can't reach later valid hits. | ||
| for (let page = 0; page < SEARCH_MAX_PROVIDER_PAGES; page++) { | ||
| const rawPage = await provider.search( | ||
| args.query, | ||
| target, | ||
| after, | ||
| minScore, | ||
| ); |
There was a problem hiding this comment.
1. Unbounded __search page size 🐞 Bug ⛨ Security
__search forwards args.first directly to provider.search (and may do so up to 16 times), so clients can request extremely large pages and cause excessive CPU/memory usage in the default provider or any custom provider. This is a DoS vector in deployments that expose __search without independent query complexity / max-list-size controls.
Agent Prompt
### Issue description
The `__search` resolver forwards unbounded `first` (and other args) to the provider. A malicious client can pass a huge `first` value, forcing large allocations/processing (especially with the default `Bm25SearchProvider` which does not cap `first`).
### Issue Context
- The SDL sets `first: Int! = 10` but provides no maximum.
- The resolver currently does not validate or cap `first` before calling the provider.
### Fix Focus Areas
- packages/semantic-introspection/src/apply.ts[91-143]
### Suggested fix
- Add argument validation in the resolver:
- Ensure `first` is an integer > 0.
- Enforce a hard max (e.g. `MAX_FIRST = 100`), either by throwing a GraphQL error when exceeded or clamping (prefer throwing to avoid surprising partial results).
- (Optional but recommended) validate `minScore` is within `[0,1]` when provided.
- (Optional) validate `query` length (e.g. 1024) to protect custom providers too.
- Ensure the capped/validated value is the one used for `target` and passed to `provider.search`.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
There was a problem hiding this comment.
This decision belongs in the gateway's security config (useMaxDepth etc). Keeping as is so behavior doesn't conflict with server configuration.
…dSchema
The earlier collision guard only covered field-name collisions on the
query type, but the extension SDL also defines two named types
(`__SearchResult` object and `__SchemaDefinition` union). A host
schema that already defined either name would, under
`extendSchema({ assumeValid: true })`, silently produce a
duplicate-extension schema rather than failing — the same failure
class the field-collision guard was meant to prevent.
The precondition now derives the type-name list from the actual
extension DocumentNode (via a small `extensionTypeNames` helper
that walks the six `*_TYPE_DEFINITION` kinds), so the guard stays in
sync if the SDL ever adds more type definitions. The thrown error
names the specific conflicting type.
Regression test constructs a host schema with `__SearchResult` via
`buildSchema(..., { assumeValid: true })` — graphql-js rejects the
`__` prefix in user-defined types otherwise — and asserts a clean
throw.
…ncapped at the library layer Adds a 'Security: client-controlled `first`' section pointing integrators at the gateway-level controls already documented in `packages/gateway/src/cli.ts`: `@escape.tech/graphql-armor-max-tokens` and `@escape.tech/graphql-armor-max-depth`. The package does not duplicate these controls because that would conflict with — and potentially over-restrict — gateway configuration that's already in place. Distinguishes from `MAX_QUERY_LENGTH` (provider-internal cost guard on tokenizer input), which is a separate concern.
|
Code review by qodo was updated up to the latest commit 6ae18ca |
1 similar comment
|
Code review by qodo was updated up to the latest commit 6ae18ca |
There was a problem hiding this comment.
Pull request overview
Introduces a new @graphql-hive/semantic-introspection workspace package that augments any GraphQLSchema with __search and __definitions fields so AI agents can discover schema capabilities by intent. It's a TypeScript port of HotChocolate's .NET reference implementation, with an additive opt-in excludeDeprecated flag that filters the agent-facing surface while leaving standard introspection untouched.
Changes:
- New package with
applySemanticIntrospection(schema, opts)non-invasively extending the schema, a default BM25 search provider (with pluggableSchemaSearchProviderinterface), and adetectEmptyAfterFilterutility. - Adds
__SearchResult,__SchemaDefinitionunion, and__search/__definitionsquery fields; collision-checked against the host schema beforeextendSchema(..., { assumeValid: true }). - Wires up workspace integration: tsconfig path alias, yarn lockfile entry, minor changeset, and 86 unit tests across 8 files.
Reviewed changes
Copilot reviewed 23 out of 25 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| packages/semantic-introspection/package.json | New package manifest (ESM/CJS dual exports, peer `graphql ^15.9 |
| packages/semantic-introspection/src/apply.ts | Schema extension entry point; collision checks, resolver wiring, paginated filter loop with safety break. |
| packages/semantic-introspection/src/schema-document.ts | SDL fragments and extend type Query builder. |
| packages/semantic-introspection/src/resolvers.ts | Coordinate lookup, deprecated/empty filtering, __SchemaDefinition union resolver (duck-typed). |
| packages/semantic-introspection/src/detect-empty-after-filter.ts | Fixed-point classifier for types empty under the deprecated filter. |
| packages/semantic-introspection/src/provider.ts | SchemaSearchProvider interface and result types. |
| packages/semantic-introspection/src/provider/bm25/bm25-search-provider.ts | Default BM25 provider; lazy index, capped query length, base64 int32 cursors, BFS path-to-root. |
| packages/semantic-introspection/src/provider/bm25/bm25-index.ts | Inverted index + BM25 scoring. |
| packages/semantic-introspection/src/provider/bm25/schema-indexer.ts | Walks schema producing BM25 docs + reverse adjacency map. |
| packages/semantic-introspection/src/provider/bm25/tokenizer.ts | ASCII-oriented tokenizer with camel/Pascal splitting. |
| packages/semantic-introspection/src/provider/bm25/document.ts | Bm25Document shape. |
| packages/semantic-introspection/src/index.ts | Public re-exports. |
| packages/semantic-introspection/tests/*.spec.ts | 8 test files covering apply, conformance, fixture matrix, empty detection, and BM25. |
| packages/semantic-introspection/README.md | Usage, options, deprecated handling, MCP recommendations, security note. |
| packages/semantic-introspection/CHANGELOG.md | Placeholder header. |
| .changeset/semantic-introspection-initial.md | Minor changeset for the initial release. |
| tsconfig.json | Adds @graphql-hive/semantic-introspection path alias. |
| yarn.lock | Adds workspace entry for the new package. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
A new package,
@graphql-hive/semantic-introspection, that adds__searchand__definitionsfields to any GraphQL schema so AI agents can discover capabilities by intent and fetch precise schema slices, without paying the token cost of full introspection.TypeScript port of the HotChocolate reference implementation by Pascal Senn and the ChilliCream team — the .NET reference released alongside the Semantic Introspection RFC. Default ranker (BM25), indexing recipe, schema additions, and result types match the .NET version.
What's added
applySemanticIntrospection(schema, opts)— non-invasive schema extension; returns a new schema (input not mutated).Bm25SearchProvider— pluggable via theSchemaSearchProviderinterface.excludeDeprecatedflag — filters@deprecatedcontent from the agent-facing surface; standard__schema/__typeintrospection remains unchanged.detectEmptyAfterFilterexported as a public utility — transitive fixed-point classifier for downstream tools that physically rewrite SDL.instructionswording for MCP servers exposing these tools over a federated graph.Notes
minor).