Phase 3: Stored Procedure Parameter Substitution (auto-embed: true)#3596
Phase 3: Stored Procedure Parameter Substitution (auto-embed: true)#3596prshri-msft wants to merge 35 commits into
auto-embed: true)#3596Conversation
There was a problem hiding this comment.
Pull request overview
Adds “Phase 3” support for stored-procedure parameter substitution via embeddings by introducing an embed: true flag on sproc parameters. At runtime, DAB converts user-provided text into an embedding vector using IEmbeddingService and substitutes the serialized vector into the sproc parameter value before execution (MSSQL only), with startup validation and unit tests covering key behaviors.
Changes:
- Extend config/schema to support
parameters[].embedand validate correct usage at startup (MSSQL + stored-proc only, embeddings enabled, no defaults). - Add
ParameterEmbeddingHelper.SubstituteEmbedParametersAsyncand wire it into REST + GraphQL stored-procedure execution paths. - Override MSSQL VECTOR parameter metadata (reported as
byte[]) to flow through the string pipeline, plus add unit tests for type override and substitution logic.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Service.Tests/UnitTests/SqlMetadataProviderUnitTests.cs | Adds unit tests for MSSQL VECTOR param type override behavior when embed: true is set. |
| src/Service.Tests/UnitTests/ParameterEmbeddingHelperTests.cs | New comprehensive unit tests for batching, validation, formatting, and cancellation in parameter embedding substitution. |
| src/Service.Tests/UnitTests/ConfigValidationUnitTests.cs | Adds unit tests for startup validation rules governing embed: true usage. |
| src/Core/Services/MetadataProviders/MsSqlMetadataProvider.cs | Applies and exposes ApplyEmbedTypeOverride to validate/override VECTOR-shaped parameters for embedding substitution. |
| src/Core/Services/Embeddings/ParameterEmbeddingHelper.cs | Implements the collect → batch → substitute pipeline to embed text parameters into vector JSON strings. |
| src/Core/Resolvers/SqlQueryEngine.cs | Wires embedding substitution into GraphQL sproc execution and REST sproc execution. |
| src/Core/Resolvers/SqlMutationEngine.cs | Wires embedding substitution into REST stored-procedure mutation execution. |
| src/Core/Resolvers/Factories/QueryEngineFactory.cs | Passes optional IEmbeddingService into SqlQueryEngine. |
| src/Core/Resolvers/Factories/MutationEngineFactory.cs | Passes optional IEmbeddingService into SqlMutationEngine. |
| src/Core/Configurations/RuntimeConfigValidator.cs | Adds ValidateEmbedParameters startup validation invoked during config validation. |
| src/Core/Azure.DataApiBuilder.Core.csproj | Adds InternalsVisibleTo to allow direct unit testing of new internal helpers. |
| src/Config/ObjectModel/ParameterMetadata.cs | Adds the Embed property and XML docs to parameter metadata. |
| schemas/dab.draft.schema.json | Adds embed to the JSON schema for stored-procedure parameter metadata. |
Spec mismatchesAcceptance criteria
Behavior bugs
Nits
|
b6bb40a to
f0649e9
Compare
Thanks for the thorough review, @JerryNixon The "type rule", "provider scope", "default values", and "empty/whitespace/null input" items together represent a meaningful redesign relative to what's currently in the PR.
|
f782cb4 to
cb1c65a
Compare
embed: true)auto-embed: true)
9d32793 to
daae1fb
Compare
Two minor improvements to RuntimeConfigValidator.ValidateEmbedParameters based on review comments on PR ajtiwari07#1. 1. Add entity-level fast-path short-circuit (line ~452) Skip entities whose parameters list contains no embed:true entry, before doing the data-source lookup and entering the inner param loop. Avoids GetDataSourceFromEntityName() and the inner foreach for the common case of entities whose params are all normal pass-through. Before: foreach entity: if Parameters is null: continue lookup data source (work) foreach param: if !Embed: continue (work, repeated per-param) ... rules ... After: foreach entity: if Parameters is null: continue if !Parameters.Any(p => p.Embed): continue (NEW fast-path) lookup data source foreach param: if !Embed: continue ... rules ... The inner !Embed continue is left in place so Rule fields (param.Name etc.) are still scoped per-param when rules fire. 2. Add TODO comment near the MSSQL-only check (line ~477) One-line // TODO: comment noting that PostgreSQL/MySQL could be supported once their metadata providers grow embed-aware type-override logic. Documents the intentional scope boundary for future contributors. Behavior preserved ------------------ - All 4 validation rules still fire identically when embed:true params are present. - Skipped entities (no embed:true params) produce the same observable behavior — the inner loop's per-param continue would have skipped them anyway. The change is pure performance; no rules are bypassed. Verification ------------ - dotnet build src/Core/Azure.DataApiBuilder.Core.csproj -c Release → Build succeeded. 0 Warning(s). 0 Error(s). - All 44 Phase 3 unit tests pass: dotnet test --filter "FullyQualifiedName~ParameterEmbeddingHelperTests |FullyQualifiedName~ValidateEmbedParameters |FullyQualifiedName~ApplyEmbedTypeOverride" → Passed: 44, Failed: 0. - The 10 ValidateEmbedParameters tests in particular still cover all 4 rules; the fast-path change doesn't bypass any of them when an embed:true param is present. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…to boolean-or-string Addresses PR Azure#3596 review feedback (Bundle 1): - AC1: Rename `embed` to `auto-embed` (JSON key) / `Embed` to `AutoEmbed` (C#). - AC2: Schema `boolean` to boolean-or-string $ref to support @env() / @akv(), matching Rest.Enabled and other DAB boolean fields. No runtime change needed -- BoolJsonConverter is registered globally. - N1 / CB3 / CB4: Rewrite schema description and ParameterMetadata XML doc; drop the inaccurate "DAB cannot detect non-VECTOR misconfigs" caveat (ApplyEmbedTypeOverride does fail-fast at startup for non-Byte[] params). - CI1: Regenerate 11 snapshot files (10 Cli.Tests, 1 Service.Tests) to include the new `AutoEmbed: false` line on sproc parameter blocks. Fixes the 3 red CI checks on the PR. Verified locally: 44 unit tests + 11 snapshot tests pass, 0 build warnings.
- CB1: Remove redundant <InternalsVisibleTo> in Core.csproj; the
[assembly:] attribute in SqlMetadataProvider.cs:26 already covers it.
- B2: Include batchResult.ErrorMessage in the embedding-failure throw so
the provider's actual reason (quota, auth, etc.) isn't dropped.
- N3: Add SubstituteEmbedParametersAsync(RuntimeConfig, entityName)
overload; 3 engine call sites collapse from 5 lines to 1.
- N2: Sort using-order in 4 files so Embeddings precedes MetadataProviders.
Verified locally: 45 tests pass, 0 build warnings.
…vice null-object Reverses the Stage 2 nullable IEmbeddingService? choice in favor of constructor- injected non-null contract per PR Azure#3596 review. - NEW src/Core/Services/Embeddings/NullEmbeddingService.cs - sealed singleton null-object. IsEnabled=false; Try* methods return failure result with an actionable error message; Embed* methods throw InvalidOperationException. - All engine + factory + helper sites change IEmbeddingService? to IEmbeddingService (no default). DI misconfiguration now fails at startup rather than as a null-reference on first request. - Startup.cs unconditionally registers IEmbeddingService - the real EmbeddingService when configured/enabled, else NullEmbeddingService.Instance. - ParameterEmbeddingHelper's null-check becomes !IsEnabled, preserving the existing 503 error verbatim for the disabled-service path. - HealthCheckHelper, EmbeddingController consume the non-null service; the health-check skip condition becomes !IsEnabled. - Updated 8 test fixtures to wire NullEmbeddingService.Instance (or set up IsEnabled on Strict mocks). Existing 28 helper tests still pass. Side benefit: removes one of the three Stage 4.4 integration-test blockers (SqlTestBase no longer needs IEmbeddingService? threading; the null-object satisfies the non-null engine ctor). Verified locally: 205 affected tests pass, 0 build warnings.
Per PR Azure#3596 review + spec Azure#3331 telemetry section. - NEW ParameterEmbeddingTelemetryHelper.cs - meter DataApiBuilder.AutoEmbedSubstitution with 2 counters (substitutions_total, params_substituted_total) + 1 histogram (duration_ms). Activity span AutoEmbed.Substitute on DABActivitySource. Tags: entity, sproc, param_names, embedding.provider, embedding.model, outcome, duration_ms. Outcomes: success | service_disabled | empty_input | non_string | batch_failure | unexpected_error. - ParameterEmbeddingHelper wrapped with Stopwatch + Activity; classified outcomes on all exit paths; defensive catch-all for unexpected errors. Structured logs (Debug/Warning/Error). Two new optional params: entityName + ILogger (engines thread their logger). Convenience overload extracts sproc name + provider/model from config for telemetry tags. - SqlMutationEngine + MutationEngineFactory gain ILogger<IMutationEngine> (matches SqlQueryEngine pattern). - 3 new telemetry tests: * SuccessfulSubstitution_EmitsActivityWithExpectedTags * FailedSubstitution_EmitsActivityWithErrorTags * Telemetry_NeverIncludesInputTextOrEmbeddingValue Uses ActivityListener to capture real spans. The never-include test verifies spec Azure#3331 data-safety requirements. Spec gap: provider status/error code and request ID require Phase 1 EmbeddingBatchResult changes (deferred). Verified locally: 31 helper tests pass (28+3), 0 build warnings.
Redesigns auto-embed parameter handling to match the authoritative spec:
- DAB is now a string-substitution layer, not a type-coercion engine.
- Sproc params must be string-compatible (nvarchar/varchar); VECTOR rejected
at startup via ValidateAutoEmbedStringCompatibility.
- Provider-neutral: MSSQL gate removed; any DB type accepted.
- Defaults allowed: omitted auto-embed params with configured defaults get
the default embedded. Empty/null defaults pass string.Empty to sproc.
- Empty/whitespace/null input: skip embedding, pass string.Empty (was 400).
Deleted: ApplyEmbedTypeOverride (~80 lines), validator Rules 0+3, 12 tests.
Added: ValidateAutoEmbedStringCompatibility, default-embedding logic,
empty-to-string.Empty pass-through, 7 spec-aligned tests.
Verified locally: 48 Phase 3 tests pass, 0 build warnings.
…date Per spec Azure#3331 CLI section. - Added [Option("parameters.auto-embed")] to EntityOptions, threaded through AddOptions and UpdateOptions constructors. - ConfigGenerator zip-loops (add + update paths) now parse autoEmbedFlags.ElementAtOrDefault(i) into ParameterMetadata.AutoEmbed. - Fixed merge bug in update path: param-merge logic at TryGetUpdatedSourceObjectWithOptions was not preserving AutoEmbed when merging CLI args with existing entity params. dab update would have silently dropped auto-embed settings. Bug found by the update test during implementation. - Updated error/deprecation messages to include auto-embed in the list. - 3 new tests: * AddEntityWithAutoEmbedParameter (DataTestMethod, 2 DataRows: auto-embed true/false, auto-embed with default value) * UpdateEntityWithAutoEmbedParameter (verifies merge preserves AutoEmbed + tests defaulting for unspecified params) Verified locally: 3 CLI tests pass, 0 build warnings.
…etadata Per spec Azure#3331 metadata section. - MCP describe_entities: added autoEmbed boolean property to each parameter entry in BuildParameterEntry. AI agents can consume this structured property to detect auto-embed parameters. - GraphQL SDL: auto-embed params get "(auto-embed: DAB converts this value to an embedding before execution)" appended to their argument description in GenerateStoredProcedureSchema. - OpenAPI REST: same description text appended to schema property description in CreateSpRequestComponentSchema. - 2 new tests: * MCP: DescribeEntities_AutoEmbedParameter_ExposedInMetadata asserts autoEmbed:true/false in JSON response * GraphQL: GenerateStoredProcedureSchema_AutoEmbedParam_Description asserts description contains/omits auto-embed indicator Verified locally: 5 MCP sproc-param tests pass, GraphQL test passes.
Per spec Azure#3331 § Error behavior, embedding-provider failures should return 502 BadGateway, not 500 InternalServerError. Updates three throw sites in ParameterEmbeddingHelper: - Batch call failed (Success=false) 500 → 502 - Batch returned wrong number of embeddings 500 → 502 - Batch returned an empty vector 500 → 502 Adds a new telemetry outcome `provider_invalid_response` for the count- mismatch and empty-vector cases, separating "provider call failed" from "provider returned bad data" in dashboards. Existing `batch_failure` outcome stays mapped to the Success=false case. Tests updated to assert the new status codes and outcome tags. Addresses review item B1 and sayalikudale's comment on ParameterEmbeddingHelper.cs:340.
…atter) The "Unit Tests" CI check is actually a `dotnet format --verify-no-changes` step that has been failing since Stage 3.13. The failure was misdiagnosed in earlier handoffs as test errors; root cause is naming-convention and unused-using violations in code added during Phase 3. Renames 9 `const` fields in the Embeddings/ directory from PascalCase to UPPER_SNAKE_CASE to match the repo convention enforced by .editorconfig (constant_fields_should_be_upper_case rule, IDE1006 severity=error): - NullEmbeddingService.DisabledMessage → DISABLED_MESSAGE - ParameterEmbeddingTelemetryHelper.Outcome* → OUTCOME_* - ParameterEmbeddingTelemetryHelper.EntityUnknown → ENTITY_UNKNOWN Telemetry tag string values (e.g., "batch_failure", "provider_invalid_ response") are unchanged — only the C# identifiers are renamed. Also removes 2 unused `using` directives in OpenApiDocumentor.cs and DescribeEntitiesTool.cs that triggered IDE0005 warnings, which --verify-no-changes treats as auto-fixable diffs.
Startup.cs never called .AddMeter() for the auto-embed meter, so the counters and histogram added in Stage 3.14 were emitted internally but silently dropped by the OTel exporter — operators saw no metrics despite all the instrumentation work. Adds the missing .AddMeter(ParameterEmbeddingTelemetryHelper.MeterName) registration next to the existing two meter registrations. Tracing was already wired correctly via .AddSource(DABActivitySource.Name). Includes a MeterListener-based regression test that proves all three instruments (auto_embed_substitutions_total, auto_embed_params_substituted_total, auto_embed_duration_ms) publish measurements with the expected names. Any future rename of an instrument would break dashboard queries in production — this test catches that at CI time. Addresses code-review finding #1a.
ConfigGenerator merged auto-embed across `dab update` with `newParam.AutoEmbed || match.AutoEmbed`, which made `true` sticky — running `dab update entity --parameters.auto-embed:false` could not disable auto-embed on an existing parameter. Root cause: the CLI build assigns AutoEmbed=false both when the user supplies "false" and when the user doesn't supply --parameters.auto-embed at all. The `||` merge couldn't distinguish those cases, so any existing `true` value won. Fix: track presence of --parameters.auto-embed at the collection level (autoEmbedFlagSupplied), then use a ternary in the merge: AutoEmbed = autoEmbedFlagSupplied ? newParam.AutoEmbed : match.AutoEmbed This preserves the existing value when the CLI flag isn't supplied, and lets the new value (true or false) win when it is. Adds a data-driven test UpdateEntity_AutoEmbedMerge with 4 rows covering every (existing × CLI) combination, including the bug case. Addresses code-review finding ajtiwari07#4.
…descriptions Stage 3.17 added auto-embed indicators to OpenAPI POST body schemas, GraphQL arguments, and MCP describe-entities. Two paths were missed (found in PR review): 1. REST GET query parameters: AddStoredProcedureInputParameters didn't receive the entity's configured ParameterMetadata, so it couldn't tell which params are auto-embed. Threads the config params through the call chain and augments the parameter description with the auto-embed indicator (mirroring the POST body path). 2. MCP custom tool input schema: BuildInputSchema's parameter description didn't surface auto-embed. Now appends the auto-embed indicator to the description so MCP clients (including LLMs) see that DAB will convert the value to an embedding before execution. The schema type stays the multi-type array — runtime validation (ParameterEmbeddingHelper) rejects non-string inputs to auto-embed params with a clear 400, so the schema doesn't need to encode that constraint. AddStoredProcedureInputParameters is changed from private to internal so a focused unit test can validate the description-augmentation logic without bootstrapping the full DI graph + MSSQL fixture used by the existing OpenApi/StoredProcedureGeneration integration tests. Adds one test per fix. Addresses code-review finding ajtiwari07#3.
XML docs and inline comments in ParameterMetadata, ParameterEmbeddingHelper, and the JSON schema description still referenced the deleted ApplyEmbedTypeOverride mechanism — "VECTOR(N) sproc parameter", "metadata override that changes VECTOR from Byte[] to String", "auto-casts to VECTOR(N)". These were accurate before Stage 3.15's redesign per spec Azure#3331 but have been misleading since. Updates 6 locations to reflect the actual contract: - sproc parameter must be a string-compatible type (NVARCHAR/VARCHAR); the sproc owns any CAST(... AS VECTOR(N)) for vector arithmetic - DAB itself is provider-neutral at the validator level; only the per-provider string-compat check lives in the metadata provider (currently only MSSQL implements it) No runtime behavior changes — comment/doc only. Addresses code-review minor finding (stale docs/comments).
…XML docs
Addresses 4 review nits from souvikghosh04:
- Remove "Phase 3:" comment prefixes from SqlQueryEngine (2),
SqlMutationEngine (1), MsSqlMetadataProvider (1)
- Remove "Per spec Azure#3331" references from MsSqlMetadataProvider XML doc,
RuntimeConfigValidator XML doc, ParameterEmbeddingHelper inline (2)
- Restore the <param> XML doc block on MutationEngineFactory's
constructor (was lost in Stage 2 when the embeddingService param
was added without updating the doc)
No runtime behavior changes; comment/doc only. Test references to
spec Azure#3331 are kept since they document why each test exists.
Addresses code-review nits from souvikghosh04 on PR Azure#3596.
…rrors
Changes the HTTP status code on all 3 auto-embed startup validation
errors from ServiceUnavailable (503) to BadRequest (400):
- MsSqlMetadataProvider.ValidateAutoEmbedStringCompatibility:
"param must be string-compatible (NVARCHAR/VARCHAR/...)"
- RuntimeConfigValidator.ValidateEmbedParameters Rule 1:
"auto-embed:true only valid on stored-procedure entities"
- RuntimeConfigValidator.ValidateEmbedParameters Rule 2:
"auto-embed:true requires runtime.embeddings configured"
Per HTTP semantics, these errors describe a misconfiguration by the
operator (a "bad request" to configure DAB this way) rather than a
transient service-unavailability condition. SubStatusCodes
(ErrorInInitialization / ConfigValidationError) are unchanged.
Note on codebase convention: many other startup config errors use
ServiceUnavailable + ErrorInInitialization. We're knowingly deviating
for the auto-embed feature based on reviewer feedback that BadRequest
is semantically more accurate for operator-config mistakes. The
broader codebase convention is out of scope.
Updates 3 test assertions and 2 DisplayName labels.
Addresses code-review ajtiwari07#6 from souvikghosh04 on PR Azure#3596.
The literal " (auto-embed: DAB converts this value to an embedding before
execution)" was hard-coded in 5 places across 3 projects (DynamicCustomTool,
OpenApiDocumentor, GraphQLStoredProcedureBuilder). Reviewer (souvikghosh04)
flagged this as repeated and asked for a refactor.
Introduces a small Azure.DataApiBuilder.Config.ObjectModel.AutoEmbedDescription
static helper with:
- internal const string Suffix — the literal (single source of truth;
visible to tests via existing
InternalsVisibleTo on the Config assembly)
- public static string? Append(string? base, bool isAutoEmbed)
— appends the suffix when isAutoEmbed; preserves null otherwise
(so OpenAPI callers can distinguish null from empty)
All 5 callsites collapse to a single Append() invocation. Output text is
byte-identical, so existing description-content assertions still pass.
Adds AutoEmbedDescriptionTests with 6 data rows pinning the helper's
behavior across (null/non-null/empty base × autoEmbed/!autoEmbed).
Addresses code-review ajtiwari07#3 and ajtiwari07#5 from souvikghosh04 on PR Azure#3596.
…coding The snapshot file UpdateEntityTests.TestConversionOfSourceObject_a70c086a74142c82.verified.txt was originally stored without a UTF-8 BOM on origin/main. Stage 3.11's regeneration of this snapshot (after the embed → auto-embed rename) inadvertently added a BOM, which shows up as a phantom line-1 diff that's visually identical to the original. Re-saves the file as UTF-8 without BOM (3 bytes removed: 0xEF 0xBB 0xBF) to match the original encoding. The 8 other snapshots Phase 3 touched correctly have BOMs that match their pre-existing convention; only this one was the outlier. No content or test behavior change. Diff vs origin/main now shows only the 3 legitimate AutoEmbed: false content additions. Addresses code-review ajtiwari07#1 from souvikghosh04 on PR Azure#3596.
Reviewer souvikghosh04 (PR Azure#3596, Startup.cs:520) flagged the embedding service registration as having unnecessary nested checks and a duplicated fallback path. Two separate `else` branches both registered `NullEmbeddingService.Instance`, distinguished only by a "configured but disabled" log — a hypothetical scenario that has no real-world usage in the repo (no test config or sample sets `embeddings.enabled: false`; users who don't want embeddings just omit the section). Collapse the three-state decision tree to a simple binary: - Enabled: configured AND IsEmbeddingsConfigured AND Enabled → register real EmbeddingService + 3 existing logs - Disabled: everything else → register NullEmbeddingService + one diagnostic log Net effect: - Nesting depth drops from 3 to 1 for the real-registration code - Two duplicate NullEmbeddingService registrations collapse into one - `EmbeddingsOptions` stays a non-nullable local - All five enabled-path log statements preserved verbatim - New single log on the disabled path replaces the previous mix of one log (for "configured but disabled") and silence (for "not configured") Behavior changes: - `EmbeddingsOptions` is no longer registered in DI when configured but disabled. Verified no consumer reads it from DI (only the inline factory captures it as a local; EmbeddingController reads via RuntimeConfigProvider). - The disabled-path now always logs once, whereas before "not configured" was silent — operator visibility is now uniform. Verified by running all 307 auto-embed / embed-parameter / embedding tests in Service.Tests — all pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CI's `dotnet format --verify-no-changes` flagged the constant declared
in Stage 3.26 as an IDE1006 naming violation. The repo .editorconfig
requires all `const` fields to be ALL_UPPER (rule
`constant_fields_should_be_upper_case`, severity=warning):
src/Config/ObjectModel/AutoEmbedDescription.cs(25,31):
error IDE1006: Naming rule violation: These words cannot contain
lower case characters: Suffix
Rename `Suffix` to `INDICATOR_SUFFIX` — keeps the meaning explicit
("the suffix used as the auto-embed indicator") while satisfying the
SCREAMING_SNAKE_CASE rule. Updates:
- AutoEmbedDescription.cs: declaration + xml <see cref> + body usage
- AutoEmbedDescriptionTests.cs: 3 DataRow attributes
Verified with focused build + 6/6 AutoEmbedDescription tests pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reviewer souvikghosh04 flagged that auto-embed:true is silently accepted on PostgreSQL/MySQL/CosmosDB at startup, then fails cryptically at request time when ParameterEmbeddingHelper substitutes a vector-JSON string into a non-string-compatible parameter. Spec Azure#3331 explicitly requires startup validation that "the database provider can support the required metadata checks" — a gap in the current implementation. Adds Rule 3 to RuntimeConfigValidator.ValidateEmbedParameters: rejects auto-embed:true on entities whose data source is not MSSQL or DWSQL (the only providers that share MsSqlMetadataProvider's auto-embed metadata path). DWSQL is included because it uses the same provider class; an end-to-end test on actual Synapse Dedicated SQL Pool is deferred to a follow-up workstream. Rule 3 is hoisted to entity-level (not per-param) since data source type is an entity-level property: - One data-source lookup per entity (not per auto-embed param) - One clear error per entity (not N duplicates) - Skips per-param Rules 1+2 for the rejected entity to avoid noise Test changes (ConfigValidationUnitTests.cs): - Removes ValidateEmbedParameters_EmbedTrue_NonMssqlDataSource_NoError, which encoded the (now-incorrect) interpretation that auto-embed is "provider-neutral". The test's premise contradicted the spec. - Replaces with ValidateEmbedParameters_EmbedTrue_ProviderSupport covering the full matrix: [MSSQL, DWSQL] → accepted [PostgreSQL, MySQL, CosmosDB_NoSQL] → rejected with BadRequest + ConfigValidationError + message naming the entity and the offending DatabaseType Verified: 13/13 ValidateEmbedParameters tests pass; 310/310 Phase 3 + embedding tests pass; build clean (0 warnings, 0 errors). Out-of-scope follow-ups (not blocking this PR): - DWSQL end-to-end test on actual Synapse Dedicated SQL Pool - sayalikudale: preserve batchResult.ErrorMessage (paused on PII) - Internal v2 critical ajtiwari07#1: raw error body log in EmbeddingService Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…otnet format
CI's Unit Tests check failed on Stage 3.30 because the new
`ValidateEmbedParameters_EmbedTrue_ProviderSupport` test method used
visual-alignment whitespace in its [DataRow] attributes:
[DataRow(DatabaseType.MSSQL, false, ...)]
[DataRow(DatabaseType.DWSQL, false, ...)]
[DataRow(DatabaseType.PostgreSQL, true, ...)]
The padding-spaces for column alignment violate `dotnet format`'s
single-space-after-comma rule. CI runs `dotnet format
--verify-no-changes` against the whole solution and fails the build
on any WHITESPACE error.
Fix: collapse to single space after each comma in 5 [DataRow] lines.
Verified locally:
- dotnet format on this file: 0 WHITESPACE/IDE errors
- Build clean (0 warnings, 0 errors)
- 13/13 ValidateEmbedParameters tests still pass
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Current main centralizes MCP integration-test engine construction in McpToolTestBase. Supply the Phase 3 NullEmbeddingService dependency through those shared constructors so the rebased test project builds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: cbd9a4b5-acd6-4fe2-ad46-5cac00d290a7
Use an explicit runtime-config lookup guard so stale or invalid entity names return the canonical EntityNotFound response instead of relying on dictionary indexer behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: cbd9a4b5-acd6-4fe2-ad46-5cac00d290a7
Document the MSSQL/DWSQL provider gate and the intentional support for parameter defaults so the XML summary matches current validation behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: cbd9a4b5-acd6-4fe2-ad46-5cac00d290a7
a27220d to
752e9f1
Compare
Implements #3331. Closes #3331.
What this PR adds
A new
auto-embed: trueflag for stored-procedure parameters. DAB acts as a string-substitution layer: takes plain text from the caller, callsIEmbeddingServicefor the vector, serializes it to a JSON array string ("[0.012,-0.045,...]"), and substitutes it as the parameter value. The sproc receives a string-compatible parameter (NVARCHAR/VARCHAR) and owns anyCAST(... AS VECTOR(N))itself.Single-call semantic search: client sends free text → DAB embeds → DB matches.
Example
Schema accepts
boolean-or-string, so"auto-embed": "@env(ENABLE_EMBED)"is also valid.Implementation
auto-embedonParameterMetadata;boolean-or-stringin schema.runtime.embeddingsmust be configured. Per-MSSQL string-compatibility check rejects non-string sproc params (VECTOR, INT, …) at startup.IEmbeddingServiceis non-optional.NullEmbeddingService.Instanceregistered when embeddings are not configured.ParameterEmbeddingHelper.SubstituteEmbedParametersAsyncruns Collect → Batch → Substitute. Defaults are honored; null/empty/whitespace →string.Empty(no API call); non-string runtime values → 400. All auto-embed params for one entity batch into a singleTryEmbedBatchAsynccall.--parameters.auto-embedondab add/dab update; preserved across updates.auto-embedsurfaced in OpenAPI, GraphQL, and MCPdescribe-entities.DataApiBuilder.AutoEmbedSubstitution(2 counters + 1 histogram) + ActivityAutoEmbed.Substitute. Tags:entity,sproc,param_names,embedding.provider,embedding.model,outcome,duration_ms. Never includes input text or vector values (spec data-safety requirement).400non-string input502provider call failed or returned malformed response (empty vector / wrong count)503embedding subsystem unavailable500reserved for DAB-internal bugsG9+InvariantCulturefor round-trip precision.Tests
54+ new unit tests, all passing in CI:
ParameterEmbeddingHelperTests(34) — full substitution helper + telemetry coverageConfigValidationUnitTests(10) — startup rulesSqlMetadataProviderUnitTests(6) — string-compatibility checkConfigurationTests,DescribeEntitiesStoredProcedureParametersTests, CLI tests — config round-trip + MCP metadata + CLI parsingManually verified end-to-end against live Azure SQL + Azure OpenAI (
text-embedding-3-small): REST POST/GET, GraphQL, MCP execute-entity; single + multi-embed-param sprocs; positive paths + input-validation + provider-failure cases.Notable design decisions
auto-embed+default; per spec, defaults are allowed and embedded when the caller omits the param.embed→auto-embedto clarify DAB does the embedding on the caller's behalf.NullEmbeddingServicenull-object moves the "is this configured?" check intoIsEnabled; DI misconfiguration now fails at startup instead of producingNullReferenceExceptionat first request.Prior review history (during #3441):
ajtiwari07/data-api-builder#1.