|
| 1 | +# pylint: disable=line-too-long,useless-suppression |
| 2 | +# ------------------------------------ |
| 3 | +# Copyright (c) Microsoft Corporation. |
| 4 | +# Licensed under the MIT License. |
| 5 | +# ------------------------------------ |
| 6 | + |
| 7 | +"""Centralized LLM validation instructions for sample execution. |
| 8 | +
|
| 9 | +This module is the single source of truth for: |
| 10 | +- instruction strings used by sample validation |
| 11 | +- mapping from sample folder -> instructions |
| 12 | +
|
| 13 | +The mapper is consumed by `sample_executor.py` to ensure all validation |
| 14 | +uses consistent instructions based on sample path. |
| 15 | +""" |
| 16 | + |
| 17 | +from __future__ import annotations |
| 18 | + |
| 19 | +from typing import Final |
| 20 | + |
| 21 | +agent_tools_instructions: Final[str] = """ |
| 22 | +We just ran Python code and captured print/log output in an attached log file (TXT). |
| 23 | +Validate whether sample execution/output is correct for a tool-driven assistant workflow. |
| 24 | +
|
| 25 | +Prefer matched/substantive data in the final output when available. |
| 26 | +
|
| 27 | +Mark `correct = false` for: |
| 28 | +- Exceptions, stack traces, explicit error/failure messages. |
| 29 | +- Timeout/auth/connection/service errors that prevent normal completion. |
| 30 | +- Malformed/corrupted output indicating broken processing. |
| 31 | +- Tool invocation failures where the sample cannot proceed as designed. |
| 32 | +
|
| 33 | +Follow-up questions are allowed, but only as supplementary behavior. |
| 34 | +If the output mainly asks follow-up questions without providing matched/substantive data, mark false. |
| 35 | +
|
| 36 | +Important distinction: |
| 37 | +- Empty tool payloads by themselves (for example `[]` or `""`) can be valid and should not automatically fail. |
| 38 | +- But if the assistant explicitly states tool failure/inability (for example "unable to retrieve ..."), |
| 39 | + treat that as a failure signal and mark `correct = false`. |
| 40 | +
|
| 41 | +Mark `correct = true` when execution succeeds and the output includes matched/substantive data, |
| 42 | +even if it also asks follow-up questions. |
| 43 | +
|
| 44 | +Always include `reason` with a concise explanation tied to the observed print output. |
| 45 | +""".strip() |
| 46 | + |
| 47 | + |
| 48 | +memories_instructions: Final[str] = """ |
| 49 | +We just ran Python code and captured print/log output in an attached log file (TXT). |
| 50 | +Validate whether sample execution/output is correct for a memories workflow. |
| 51 | +
|
| 52 | +For memories scenarios, successful output typically shows one or more of: |
| 53 | +- Memory store/session creation or retrieval steps. |
| 54 | +- Memory save/ingest operations. |
| 55 | +- Memory query/search output with relevant recalled content. |
| 56 | +
|
| 57 | +Mark `correct = false` for: |
| 58 | +- Exceptions, stack traces, explicit error/failure messages. |
| 59 | +- Timeout/auth/connection/service errors that prevent normal completion. |
| 60 | +- Malformed/corrupted output indicating broken processing. |
| 61 | +- Memory operation failures where the sample cannot proceed as designed. |
| 62 | +
|
| 63 | +Important distinction: |
| 64 | +- Empty memory results by themselves (for example no matches for a query) can be valid and should not automatically fail. |
| 65 | +- Completed updates with 0 memory operations can still be valid for this test and should not automatically fail. |
| 66 | +- But explicit inability/failure to access or process memory should be marked `correct = false`. |
| 67 | +
|
| 68 | +Mark `correct = true` when execution succeeds and the output is consistent with the sample's intended |
| 69 | +memory behavior, even if no memory matches are found. |
| 70 | +
|
| 71 | +Always include `reason` with a concise explanation tied to the observed print output. |
| 72 | +""".strip() |
| 73 | + |
| 74 | + |
| 75 | +agents_instructions: Final[str] = """ |
| 76 | +We just ran Python code and captured print/log output in an attached log file (TXT). |
| 77 | +Validate whether sample execution/output is correct. |
| 78 | +
|
| 79 | +For agents scenarios, successful output typically shows one or more of: |
| 80 | +- Agent/run/thread creation or execution progress. |
| 81 | +- Assistant response content, streamed events, or structured output. |
| 82 | +- Retrieval/context-aware response behavior when the sample asks for it. |
| 83 | +
|
| 84 | +Check input/output correspondence: |
| 85 | +- If the printed output contains a user prompt/request/question, the final assistant output should |
| 86 | + clearly address that input and stay on-topic. |
| 87 | +- If the sample expects structured output, the printed result should match that structure. |
| 88 | +- Minor wording differences are acceptable as long as the response is relevant and logically consistent. |
| 89 | +
|
| 90 | +Mark `correct = false` for: |
| 91 | +- Exceptions, stack traces, explicit error/failure messages. |
| 92 | +- Timeout/auth/connection/service errors that prevent normal completion. |
| 93 | +- Malformed/corrupted output indicating broken processing. |
| 94 | +- Agent run/tool/retrieval failures where the sample cannot proceed as designed. |
| 95 | +
|
| 96 | +Important distinction: |
| 97 | +- Intermediate/partial prints during streaming can be valid and should not automatically fail. |
| 98 | +- Empty or brief intermediate payloads by themselves can be valid if the run still completes successfully. |
| 99 | +- But explicit inability/failure to execute the intended agent workflow should be marked `correct = false`. |
| 100 | +
|
| 101 | +Mark `correct = true` when execution succeeds and the output is consistent with the sample's intended |
| 102 | +agent behavior, including reasonable correspondence between input prompt(s) and final output. |
| 103 | +
|
| 104 | +Always include `reason` with a concise explanation tied to the observed print output. |
| 105 | +""".strip() |
| 106 | + |
| 107 | + |
| 108 | +chat_completions_instructions: Final[str] = """ |
| 109 | +We just ran Python code and captured print/log output in an attached log file (TXT). |
| 110 | +Validate whether sample execution/output is correct for Chat Completions scenarios. |
| 111 | +
|
| 112 | +Successful output typically shows one or more of: |
| 113 | +- A user prompt and a corresponding assistant response. |
| 114 | +- Reasonable, on-topic completion content. |
| 115 | +
|
| 116 | +Mark `correct = false` for: |
| 117 | +- Exceptions, stack traces, explicit error/failure messages. |
| 118 | +- Timeout/auth/connection/service errors that prevent normal completion. |
| 119 | +- Malformed/corrupted output indicating broken processing. |
| 120 | +- Output that clearly does not answer the prompt in the sample. |
| 121 | +
|
| 122 | +Mark `correct = true` when execution succeeds and the assistant output is coherent and |
| 123 | +responds to the printed prompt, even if the exact wording varies. |
| 124 | +
|
| 125 | +Always include `reason` with a concise explanation tied to the observed print output. |
| 126 | +""".strip() |
| 127 | + |
| 128 | + |
| 129 | +resource_management_instructions: Final[str] = """ |
| 130 | +We just ran Python code and captured print/log output in an attached log file (TXT). |
| 131 | +Validate whether sample execution/output is correct for resource-management samples (for example |
| 132 | +connections, files, and deployments). |
| 133 | +
|
| 134 | +Successful output typically shows one or more of: |
| 135 | +- Create/get/list/update/delete operations completing as expected. |
| 136 | +- Returned resource objects/IDs/names/versions or other meaningful operation results. |
| 137 | +- Consistent progress from setup to cleanup where applicable. |
| 138 | +
|
| 139 | +Mark `correct = false` for: |
| 140 | +- Exceptions, stack traces, explicit error/failure messages. |
| 141 | +- Timeout/auth/connection/service errors that prevent normal completion. |
| 142 | +- Malformed/corrupted output indicating broken processing. |
| 143 | +- Operation failures where the sample cannot proceed as designed. |
| 144 | +
|
| 145 | +Important distinction: |
| 146 | +- Empty list results by themselves can be valid and should not automatically fail. |
| 147 | +- Cleanup/delete operations that report not found may still be acceptable if the sample otherwise succeeds. |
| 148 | +- But explicit inability/failure for required core operations should be marked `correct = false`. |
| 149 | +
|
| 150 | +Mark `correct = true` when execution succeeds and output is consistent with the sample's intended |
| 151 | +resource-management behavior. |
| 152 | +
|
| 153 | +Always include `reason` with a concise explanation tied to the observed print output. |
| 154 | +""".strip() |
| 155 | + |
| 156 | + |
| 157 | +fine_tuning_instructions: Final[str] = """ |
| 158 | +We just ran Python code and captured print/log output in an attached log file (TXT). |
| 159 | +Validate whether sample execution/output is correct for a fine-tuning workflow. |
| 160 | +
|
| 161 | +Successful output typically shows one or more of: |
| 162 | +- Training/validation files prepared or uploaded successfully. |
| 163 | +- Fine-tuning job creation with a returned job id/name. |
| 164 | +- Job details/status output that indicates the request was accepted and processed. |
| 165 | +
|
| 166 | +Mark `correct = false` for: |
| 167 | +- Exceptions, stack traces, explicit error/failure messages. |
| 168 | +- Authentication/authorization/service errors that block job creation. |
| 169 | +- File upload/read failures for required training/validation data. |
| 170 | +- Fine-tuning job creation failures or malformed output that indicates broken processing. |
| 171 | +
|
| 172 | +Important distinction: |
| 173 | +- Intermediate/transitional job states (for example queued/running) are valid and should not fail by themselves. |
| 174 | +- The output does not need to show completed training unless the sample is explicitly designed to wait for completion. |
| 175 | +
|
| 176 | +Mark `correct = true` when execution succeeds and output is consistent with initiating/inspecting |
| 177 | +the intended fine-tuning workflow. |
| 178 | +
|
| 179 | +Always include `reason` with a concise explanation tied to the observed print output. |
| 180 | +""".strip() |
| 181 | + |
| 182 | + |
| 183 | +evaluations_instructions: Final[str] = """ |
| 184 | +We just ran Python code for an evaluation sample and captured print/log output in an attached log file (TXT). |
| 185 | +Your job: determine if the sample code executed to completion WITHOUT throwing an unhandled exception. |
| 186 | +
|
| 187 | +Respond TRUE (correct=true) if: |
| 188 | +- The output shows the evaluation was created and produced results (any results, including zeros) |
| 189 | +- The sample ran to completion (no unhandled Python exceptions/tracebacks) |
| 190 | +- Evaluation metric JSON with fields like "failed": 0, "error": null, "not_applicable": 0 is NORMAL |
| 191 | + successful output — these are counters, NOT errors |
| 192 | +- Status messages like "in_progress", "Waiting for eval run" are normal polling behavior |
| 193 | +- HTTP debug headers (x-stainless-read-timeout, x-ms-client-request-id, etc.) are normal and irrelevant |
| 194 | +- "deleted": true/false in cleanup output is normal |
| 195 | +- The absence of explicit "success" text is fine — no crash means success |
| 196 | +
|
| 197 | +Respond FALSE (correct=false) ONLY if: |
| 198 | +- There is an actual Python traceback or unhandled exception |
| 199 | +- There is an explicit error message like "Evaluation run failed" or "FAILED_EXECUTION" |
| 200 | +- There is an actual timeout error or connection failure (NOT an HTTP header containing "timeout") |
| 201 | +- The output shows corrupted or malformed data that prevented completion |
| 202 | +
|
| 203 | +Always respond with `reason` indicating the reason for the response. |
| 204 | +""".strip() |
| 205 | + |
| 206 | + |
| 207 | +# Folder (under samples/) -> instructions. |
| 208 | +# Keys intentionally mirror the folder names used by sample test discovery. |
| 209 | +# Use the most specific key possible (e.g. "agents/tools" should win over "agents"). |
| 210 | +INSTRUCTIONS_BY_FOLDER: Final[dict[str, str]] = { |
| 211 | + "agents/tools": agent_tools_instructions, |
| 212 | + "agents": agents_instructions, |
| 213 | + "memories": memories_instructions, |
| 214 | + "connections": resource_management_instructions, |
| 215 | + "files": resource_management_instructions, |
| 216 | + "deployments": resource_management_instructions, |
| 217 | + "datasets": resource_management_instructions, |
| 218 | + "chat_completions": chat_completions_instructions, |
| 219 | + "finetuning": fine_tuning_instructions, |
| 220 | + "evaluations/agentic_evaluators": evaluations_instructions, |
| 221 | + "evaluations": evaluations_instructions, |
| 222 | +} |
| 223 | + |
| 224 | + |
| 225 | +def get_instructions_for_sample_path(sample_path: str) -> str: |
| 226 | + """Return the appropriate instruction string for a given sample path. |
| 227 | +
|
| 228 | + The sample path may be absolute or relative and may use either '\\' or '/'. |
| 229 | + Matching is done against the path segment under the `samples/` directory. |
| 230 | +
|
| 231 | + Falls back to resource_management_instructions when no folder match is found. |
| 232 | + """ |
| 233 | + |
| 234 | + normalized = str(sample_path).replace("\\", "/") |
| 235 | + |
| 236 | + # Find the portion after /samples/ |
| 237 | + marker = "/samples/" |
| 238 | + relative = normalized |
| 239 | + if marker in normalized: |
| 240 | + relative = normalized.split(marker, 1)[1] |
| 241 | + |
| 242 | + # Reduce to folder prefix (everything except filename) |
| 243 | + folder = "/".join([p for p in relative.split("/") if p][:-1]) |
| 244 | + |
| 245 | + # Longest-prefix match on INSTRUCTIONS_BY_FOLDER keys. |
| 246 | + for key in sorted(INSTRUCTIONS_BY_FOLDER.keys(), key=len, reverse=True): |
| 247 | + if folder == key or folder.startswith(f"{key}/"): |
| 248 | + return INSTRUCTIONS_BY_FOLDER[key] |
| 249 | + |
| 250 | + return resource_management_instructions |
0 commit comments