Search Test #6
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Search Test | |
| on: | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| jobs: | |
| websearch-smoke: | |
| name: Web Search Smoke Test | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Validate required secrets | |
| env: | |
| TAVILY_API_KEY: ${{ secrets.TAVILI_API_KEY }} | |
| MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }} | |
| run: | | |
| if [ -z "${TAVILY_API_KEY:-}" ]; then | |
| echo "::error::Missing repository secret TAVILY_API_KEY" | |
| exit 1 | |
| fi | |
| if [ -z "${MISTRAL_API_KEY:-}" ]; then | |
| echo "::error::Missing repository secret MISTRAL_API_KEY" | |
| exit 1 | |
| fi | |
| - name: Run websearch examples | |
| env: | |
| WEB_SEARCH_PROVIDER: tavily | |
| TAVILY_API_KEY: ${{ secrets.TAVILI_API_KEY }} | |
| MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }} | |
| run: | | |
| set -euo pipefail | |
| run_query() { | |
| local query="$1" | |
| echo "Running query: $query" | |
| local output | |
| output="$(npm run --silent oneshot -- websearch --json -q "$query")" | |
| echo "$output" | node -e ' | |
| const fs = require("fs"); | |
| const raw = fs.readFileSync(0, "utf8").trim(); | |
| const candidates = raw | |
| .split(/\r?\n/) | |
| .map((line) => line.trim()) | |
| .filter(Boolean) | |
| .reverse(); | |
| let parsed; | |
| let parseErrorMessage = ""; | |
| for (const line of candidates) { | |
| const isJsonCandidate = line.startsWith("[") || line.startsWith("{"); | |
| if (!isJsonCandidate) { | |
| continue; | |
| } | |
| try { | |
| parsed = JSON.parse(line); | |
| break; | |
| } catch (error) { | |
| parseErrorMessage ||= error instanceof Error ? error.message : String(error); | |
| } | |
| } | |
| if (parsed === undefined) { | |
| console.error( | |
| `Expected valid JSON output from websearch.${parseErrorMessage ? ` Last parse error: ${parseErrorMessage}` : ""}` | |
| ); | |
| process.exit(1); | |
| } | |
| if (!Array.isArray(parsed)) { | |
| console.error("Expected JSON array of search results.", parsed); | |
| process.exit(1); | |
| } | |
| if (parsed.length === 0) { | |
| console.error("Expected at least one search result."); | |
| process.exit(1); | |
| } | |
| for (const item of parsed.slice(0, 3)) { | |
| if (typeof item.title !== "string" || typeof item.link !== "string" || typeof item.snippet !== "string") { | |
| console.error("Malformed search result:", item); | |
| process.exit(1); | |
| } | |
| } | |
| ' | |
| } | |
| run_query "Anthropic docs model context protocol" | |
| run_query "LangChain TypeScript agent loop example" | |
| run_query "GitHub Actions setup-node cache npm" |