@@ -22,6 +22,37 @@ namespace Azure.DataApiBuilder.Core.Services.Embeddings;
2222/// </summary>
2323public static class ParameterEmbeddingHelper
2424{
25+ /// <summary>
26+ /// Convenience overload that resolves the entity's <see cref="ParameterMetadata"/> from
27+ /// the runtime config by entity name, then delegates to the parameter-list overload.
28+ ///
29+ /// All three engine call sites (SqlQueryEngine GraphQL path, SqlQueryEngine REST path,
30+ /// SqlMutationEngine REST path) follow the same lookup-then-substitute pattern; this
31+ /// overload centralizes it so the engines don't each carry the boilerplate.
32+ /// </summary>
33+ /// <param name="resolvedParams">
34+ /// The parameter dictionary from the request. Modified in-place: text values for
35+ /// auto-embed params are replaced with vector JSON strings.
36+ /// </param>
37+ /// <param name="runtimeConfig">The active runtime config (resolved via the provider at the call site).</param>
38+ /// <param name="entityName">Name of the stored-procedure entity whose parameters may need embedding.</param>
39+ /// <param name="embeddingService">The embedding service to call for text → vector conversion.</param>
40+ /// <param name="cancellationToken">Cancellation token from the HTTP request.</param>
41+ public static Task SubstituteEmbedParametersAsync (
42+ IDictionary < string , object ? > resolvedParams ,
43+ RuntimeConfig runtimeConfig ,
44+ string entityName ,
45+ IEmbeddingService ? embeddingService ,
46+ CancellationToken cancellationToken )
47+ {
48+ Entity entity = runtimeConfig . Entities [ entityName ] ;
49+ return SubstituteEmbedParametersAsync (
50+ resolvedParams ,
51+ entity . Source . Parameters ,
52+ embeddingService ,
53+ cancellationToken ) ;
54+ }
55+
2556 /// <summary>
2657 /// For each parameter marked auto-embed:true in config, replaces the text value in
2758 /// resolvedParams with a serialized vector string.
@@ -162,12 +193,17 @@ public static async Task SubstituteEmbedParametersAsync(
162193
163194 if ( ! batchResult . Success || batchResult . Embeddings is null )
164195 {
165- // Batch failure: we lose per-param error specificity here, but the
166- // batch result's ErrorMessage typically explains the underlying issue.
167- // Naming all involved params helps the user identify the request context.
196+ // Batch failure: include the provider's ErrorMessage when available so the caller
197+ // sees the actual reason (e.g., quota exhausted, model not found, authentication
198+ // failed) rather than only the generic "Failed to generate embeddings" line.
199+ // Per-param specificity is lost at the batch level, so naming all involved params
200+ // helps identify the request context.
168201 string paramNames = string . Join ( ", " , embedRequests . Select ( r => $ "'{ r . paramName } '") ) ;
202+ string providerDetail = string . IsNullOrWhiteSpace ( batchResult . ErrorMessage )
203+ ? string . Empty
204+ : $ " Provider error: { batchResult . ErrorMessage } ";
169205 throw new DataApiBuilderException (
170- message : $ "Failed to generate embeddings for parameter(s) { paramNames } .",
206+ message : $ "Failed to generate embeddings for parameter(s) { paramNames } .{ providerDetail } ",
171207 statusCode : HttpStatusCode . InternalServerError ,
172208 subStatusCode : DataApiBuilderException . SubStatusCodes . UnexpectedError ) ;
173209 }
0 commit comments