Repository navigation
Conversation
|
Azure Pipelines: Successfully started running 1 pipeline(s). 10 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
There was a problem hiding this comment.
Copilot encountered an error: Your billing is not configured or you have Copilot licenses from multiple standalone organizations or enterprises. To use premium requests, select a billing entity via the GitHub site, under Settings > Copilot > Features.
There was a problem hiding this comment.
Copilot encountered an error: Your billing is not configured or you have Copilot licenses from multiple standalone organizations or enterprises. To use premium requests, select a billing entity via the GitHub site, under Settings > Copilot > Features.
There was a problem hiding this comment.
Copilot encountered an error: Your billing is not configured or you have Copilot licenses from multiple standalone organizations or enterprises. To use premium requests, select a billing entity via the GitHub site, under Settings > Copilot > Features.
There was a problem hiding this comment.
Copilot encountered an error: Your billing is not configured or you have Copilot licenses from multiple standalone organizations or enterprises. To use premium requests, select a billing entity via the GitHub site, under Settings > Copilot > Features.
There was a problem hiding this comment.
Copilot encountered an error: Your billing is not configured or you have Copilot licenses from multiple standalone organizations or enterprises. To use premium requests, select a billing entity via the GitHub site, under Settings > Copilot > Features.
There was a problem hiding this comment.
Copilot encountered an error: Your billing is not configured or you have Copilot licenses from multiple standalone organizations or enterprises. To use premium requests, select a billing entity via the GitHub site, under Settings > Copilot > Features.
There was a problem hiding this comment.
Copilot encountered an error: Your billing is not configured or you have Copilot licenses from multiple standalone organizations or enterprises. To use premium requests, select a billing entity via the GitHub site, under Settings > Copilot > Features.
Replace the OpenAI-specific runner path with a small DecisionProtocol adapter layer. The runner selects the Microsoft or OpenAI adapter from decision_protocol, and each adapter only translates the canonical request and binds answers back to the canonical shape, so evaluators keep their scoring, applicability and cutoffs unchanged. - OpenAI score levels are labeled Level 1 to Level n, matching rubric text such as "imply level 2"; answers still bind by zero-based level index. - Byte budgets measure the canonical request on every protocol, and invalid evidence fails with the same user error on every protocol. - A refusal fails only when an evaluator reads it (error_kind model_refusal), and a provider content filter rejection is marked error_kind content_filter. - Provenance and execution metrics name the protocol and keep provider cache and reasoning counters under usage_details. Split conversations sum each counter over the turns whose token usage is counted, on success and on failure, so the counters never cover requests the token totals omit. - Each evaluation run through DecisionEvaluationStrategy.evaluate records the optional OpenTelemetry metrics azure.ai.evaluation.decision.evaluations and azure.ai.evaluation.decision.evaluation.duration with protocol, metric, outcome, blame and error_kind. The runner marks a cancellation by the cancellation callback, so it is recorded as cancelled even when its execution summary is omitted. A metric sink or OpenTelemetry failure never changes the result or the error.
The sample now imports CoherenceEvaluator from azure.ai.evaluation, which accepts a Decision model configuration in 1.18.11, instead of requiring an azureml-assets checkout. It also notes the error for a deployment that serves the other protocol, and that GPT-6 Luna used as a chat judge needs is_reasoning_model=True.
…tocol A Decision deployment that serves the other protocol now fails with a hint that names the decision_protocol value to use: Microsoft Decision answers such a deployment with unknown_model and Azure OpenAI Decisions with model_not_found. Other errors are unchanged.
ee99b73 to
c0b6931
Compare
…der, and name Decision failure reasons (#49804) * Reuse credential tokens across model requests and fix Tool Call Success scoring Token reuse (from #49695, without the OpenAI Decisions protocol): - Decision requests, and Azure OpenAI chat requests that use Microsoft Entra ID, reuse a credential's token until five minutes before it expires instead of requesting one per request. - Concurrent requests that share a synchronous credential wait for one token request, off the event loop; requests queued behind a token that is not cached use it. - A 401 drops the token, and an acquisition that began before the rejection is not stored. - The default chat credential shares one credential and token across concurrent first requests. - A Decision credential that returns no string token is a user error, not a timeout. Tool Call Success: - The prompt's 14 example outputs are now valid JSON, which stops gpt-4.1 and gpt-4o nesting score and status in properties and scoring successful tool calls 0. - score, status and reason fall back to properties, and a score other than 0 or 1 raises a system error instead of becoming 0. - A list of messages without tool calls (only text or MCP approvals) is not applicable without a judge call; strings, tool traces in text and any other content still go to the judge. * Share the chat token scope with Decision requests and drop the redundant retry list Decision requests now request tokens for https://ai.azure.com/.default, the scope Azure OpenAI chat requests use, so a credential shared by chat and Decision evaluators needs one token instead of one per scope. Decision endpoints accept both audiences. The explicit retry status list is removed: azure-core retries those statuses by default and unions an explicit list with its defaults, so retry behavior is unchanged. _get_token documents its absolute monotonic deadline, and the token cache module records why get_bearer_token_provider is not used in its place. * Name the reason a failed Decision request was refused, and share only authentication failures with waiting requests A failed Decision request names a recognized reason in decision_model.error_kind of the error's properties, which is kept on failed result rows, and in the error message, for example "The decision model returned HTTP 422 (context_window_exceeded).". The provider states these reasons for an HTTP 422 only in text, which is never exposed: context_window_exceeded, request_token_limit_exceeded, question_limit_exceeded and invalid_question, recognized by the sentence's fixed opening so a quoted question identifier cannot change the kind. A request over max_request_bytes or max_state_question_bytes, which is not sent, has the kind request_bytes_exceeded. Requests that waited on a token request now share its failure only when it failed authentication, as on the chat path; after any other failure each waiting request makes its own attempt, so a transient failure fails only the request that hit it. * Keep Decision on the Cognitive Services scope and keep token failures within each kind of request Decision endpoints accept both audiences, but the hosted evaluation service selects the identity for Decision calls by token audience: for https://ai.azure.com it forwards the caller's own token, and for the Cognitive Services audience it exchanges that token or uses the project managed identity. With the chat scope, single-tenant projects would call Decision as the end user instead of the project managed identity, and the service's worker tests fail. Decision requests go back to https://cognitiveservices.azure.com/.default and their own cached token, and the redundant retry status list stays removed. The token cache records a failure per failure formatter and exception type, with the attempt that ended in it, so a request shares only a failure of its own kind that ended after it queued, and a successful token request clears them. A request could otherwise replay another kind's failure with its own exception type: a Decision description raised as a chat ClientAuthenticationError, or a chat authentication failure raised as an EvaluationException with an unknown blame. A credential that implements AsyncTokenCredential but whose get_token is a plain function returning an awaitable was asked on a worker thread, where a get_token that needs the running event loop failed. A credential whose get_token is a coroutine function, or that implements AsyncTokenCredential, is now asked on the caller's event loop, as released chat requests did. * Format the Decision error-kind patterns and tests with black The package enforces black, and these lines were not formatted. No code changes. * Format the Decision batch persistence test with black The Analyze job's black check failed on this file. No code changes. * Ask credentials that also implement the synchronous context manager protocol on a worker thread A synchronous credential whose class also implements the asynchronous context manager protocol matched the structural AsyncTokenCredential check and was asked on the event loop, which blocked the loop, lost the shared token request and broke a get_token that runs its own event loop. A credential that implements the synchronous context manager protocol is again asked on a worker thread. A plain get_token that needs the caller's running loop must belong to an AsyncTokenCredential, as the CHANGELOG and docstrings now state, and fetch documents that its failure formatter and exception type key the shared failures and must be module-level. * Move token reuse to its own pull request Token reuse for Decision and chat requests is not part of the Tool Call Success and Decision failure reason fixes, so it moves to a separate pull request. This restores the base _prompty.py and _async_token_provider.py, removes _token_cache.py and its tests, and returns DecisionModelRunner to requesting a token for each call, with the Cognitive Services scope as before. The error_kind reasons, the retry policy cleanup and the Tool Call Success fixes are unchanged. * Treat empty tool call fields as absent in Tool Call Success A tool_calls, function_call or tool_call_id field that is None or an empty string, list or dict no longer sends a text-only response to the judge. OpenAI's model_dump() writes tool_calls: None and function_call: None on every reply, so those replies reached the chat or Decision judge and could pass. Populated fields and values of any other type still go to the judge. * Count only passed and failed rows in binary_aggregate evaluate() divided an evaluator's passes by every row, so not applicable and errored rows counted as failures and binary_aggregate disagreed with the mean score. It now divides by the rows that passed or failed, and an evaluator without such rows gets no binary_aggregate, as one without scores gets no mean. * Keep evaluator inputs in their declared order _get_all_singleton_inputs flattened the overloads' input names through a set, so an evaluator's converted inputs followed the set's order, which varies with the process's hash seed. An evaluator that sends these inputs to a Decision model unchanged, as several Microsoft Foundry catalog evaluators do, could therefore list the same fields in a different order in each process, and the Decision model could answer the same input differently. The names now keep the order in which the overloads declare them. The built-in evaluators in this package build their Decision state in a fixed order and are unchanged. * Keep the last result column deciding binary_aggregate An evaluator with several _result columns reports its last one, as before. A last column without pass or fail rows now leaves no binary_aggregate instead of an earlier column's rate. The CHANGELOG says only pass and fail count, which also affects custom evaluators that return other values. Tests cover all-fail and boolean result columns, several result columns, and OpenAI tool calls on the Decision judge. * Run the hash seed test's processes from an empty directory python -c puts the working directory first on the path, so in CI jobs that install the built wheel and run pytest from the package directory, the child processes imported the checkout instead of the installed package. They now start in an empty temporary directory, and three seeds keep the test short. * Leave unsupported role and content type values to the judge The no-tool-call check compared role and content type values with sets, so an unhashable value, such as a list role or a dict type, raised TypeError. A value that is not a string now fails the check, so the message goes to the judge or the input validator, as it did before the check existed. --------- Co-authored-by: Ahmad Qardahji <aqardahji@microsoft.com>
Existing Decision evaluators speak the Microsoft Decision contract. This adds a small protocol adapter layer to the shared runner from #49486, so
decision_protocol="openai"calls Azure OpenAI's/openai/v1/decisionsand existing configurations keep the Microsoft route.DecisionProtocolhas three operations: the operation URL, encoding the canonical request, and binding answers back to the canonical shape.MicrosoftDecisionProtocolis the identity;OpenAIDecisionProtocolturns Boolean questions into predicates that state both criteria, ordinal criteria into levels labeledLevel 1toLevel n(matching rubric text such as "imply level 2"), and binds answers by name and zero-based level index. Evaluators keep their scoring, applicability and cutoffs, and provenance has the same shape on both protocols apart fromprotocoland the returned model.error_kindmodel_refusal), so skipped evaluations never depend on their grade. A provider content filter's 400 is markedcontent_filter.decision_protocolvalue to use. Microsoft Decision answers such a deployment withunknown_modeland Azure OpenAI Decisions withmodel_not_found; other errors are unchanged.protocol, and cache and reasoning counters stay underusage_details. Split conversations sum each counter over the turns whose token usage is counted, on success and on failure.DecisionEvaluationStrategy.evaluaterecordsazure.ai.evaluation.decision.evaluationsandazure.ai.evaluation.decision.evaluation.durationwithprotocol,metric,outcome(completed,skipped,errororcancelled),blameanderror_kind. A cancellation by the cancellation callback counts ascancelled, and a metric or OpenTelemetry failure never changes the result or the error.The same Decision-capable assets are reused unchanged; assets #5402 adds tests only. On the service side, the RAISvc worker selects this adapter from its validated binding in a separate vienna change that has not merged; the worker on vienna master uses the Microsoft protocol only, and its validation no longer treats OpenAI decision-capable deployments as native Decision models. #49781, which lets the SDK's built-in evaluators use Decision models and record these metrics, has merged and this PR is rebased on it; the OpenAI Decisions sample (
samples/openai_decisions/README.md) uses the publicCoherenceEvaluator. Token reuse moved to #49804.Validation:
decision_protocol="openai"against agpt-6-lunadeployment: every built-in evaluator,QAEvaluatorand three two-turn conversations completed withprotocolopenai, and the evaluation metric counts matched every call. A Microsoft Decision deployment, a GPT-6 Luna deployment and a chat deployment each returned the protocol hint when configured with the wrong protocol.evaluate(): every built-in evaluator completed on Decision and chat judges with no errors.probability_thresholdincident cases on Decision and chat judges.evaluate()with every built-in evaluator andQAEvaluatorpassed on the Microsoft Decision judge and on gpt-4.1, gpt-4o, gpt-5-mini and o3-mini. Chat results match 1.18.10.The azureml-assets #5402 suite passes on this code (1,259 passed, including all 106 OpenAI Decisions cases) once its SDK pin moves here together with its updated OpenAI tests. No package release is performed by this PR. API contract.