validateSamplesForTool validates each sample against the named MCP tool's inputSchema after stripping recognized sidecar fields.
(toolName string, samples []map[string]any)
| 149 | // validateSamplesForTool validates each sample against the named MCP tool's |
| 150 | // inputSchema after stripping recognized sidecar fields. |
| 151 | func validateSamplesForTool(toolName string, samples []map[string]any) error { |
| 152 | schemas, err := getCompiledToolSchemas() |
| 153 | if err != nil { |
| 154 | return err |
| 155 | } |
| 156 | entry, found := schemas[toolName] |
| 157 | if !found { |
| 158 | if sampleValidationDeferredTools[toolName] { |
| 159 | samplesValidationLog.Printf("Deferring sample validation for dynamic tool %q to runtime", toolName) |
| 160 | return nil |
| 161 | } |
| 162 | return fmt.Errorf("samples: no MCP tool schema found for %q (yaml key %q). Available tools come from pkg/workflow/js/safe_outputs_tools.json", toolName, toolDisplayKey(toolName)) |
| 163 | } |
| 164 | displayKey := toolDisplayKey(toolName) |
| 165 | sidecars := sampleSidecarFields[toolName] |
| 166 | for i, sample := range samples { |
| 167 | stripped := stripSidecarFields(sample, sidecars) |
| 168 | substituted, ok := substituteRuntimeExpressionsForValidation(stripped, entry.raw).(map[string]any) |
| 169 | if !ok { |
| 170 | substituted = stripped |
| 171 | } |
| 172 | if err := entry.compiled.Validate(substituted); err != nil { |
| 173 | return fmt.Errorf("safe-outputs.%s.samples[%d]: %w", displayKey, i, err) |
| 174 | } |
| 175 | } |
| 176 | return nil |
| 177 | } |
| 178 | |
| 179 | // substituteRuntimeExpressionsForValidation returns a deep copy of v in which |
| 180 | // every string value containing a `${{ ... }}` GitHub Actions expression has |