|
| 1 | +import { Stagehand } from "../lib/v3"; |
| 2 | + |
| 3 | +/** |
| 4 | + * Test script to verify custom fetch and headers are forwarded to AI SDK providers |
| 5 | + * |
| 6 | + * This demonstrates the fix for the bug where custom fetch functions and headers |
| 7 | + * were being silently ignored when using AI SDK providers (e.g., "openai/gpt-4o-mini"). |
| 8 | + * |
| 9 | + * Expected behavior: |
| 10 | + * - Custom fetch function should be called for all LLM API requests |
| 11 | + * - Custom headers should be included in the requests |
| 12 | + * - This enables use cases like: proxy authentication, request logging, retry logic |
| 13 | + */ |
| 14 | + |
| 15 | +async function main() { |
| 16 | + // Track if custom fetch was called |
| 17 | + let fetchCallCount = 0; |
| 18 | + const customHeaders: string[] = []; |
| 19 | + |
| 20 | + // Create custom fetch function |
| 21 | + const customFetch: typeof fetch = async (url, options) => { |
| 22 | + fetchCallCount++; |
| 23 | + console.log(`✅ Custom fetch called (${fetchCallCount} times)`); |
| 24 | + console.log(` URL: ${url}`); |
| 25 | + |
| 26 | + // Log custom headers if present |
| 27 | + if (options?.headers) { |
| 28 | + const headers = new Headers(options.headers); |
| 29 | + headers.forEach((value, key) => { |
| 30 | + if (key.toLowerCase().startsWith('x-custom')) { |
| 31 | + customHeaders.push(`${key}: ${value}`); |
| 32 | + console.log(` Custom header: ${key}: ${value}`); |
| 33 | + } |
| 34 | + }); |
| 35 | + } |
| 36 | + |
| 37 | + return fetch(url, options); |
| 38 | + }; |
| 39 | + |
| 40 | + // Initialize Stagehand with custom fetch and headers |
| 41 | + console.log("Initializing Stagehand with custom fetch and headers...\n"); |
| 42 | + |
| 43 | + const stagehand = new Stagehand({ |
| 44 | + model: { |
| 45 | + modelName: "openai/gpt-4o-mini", |
| 46 | + apiKey: process.env.OPENAI_API_KEY, |
| 47 | + fetch: customFetch, |
| 48 | + headers: { |
| 49 | + "X-Custom-Header": "test-value", |
| 50 | + "X-Custom-Proxy-Auth": "proxy-token-123" |
| 51 | + } |
| 52 | + }, |
| 53 | + env: "LOCAL" |
| 54 | + }); |
| 55 | + |
| 56 | + await stagehand.init(); |
| 57 | + |
| 58 | + try { |
| 59 | + console.log("Making a simple LLM call via act()...\n"); |
| 60 | + |
| 61 | + // Navigate to a simple page |
| 62 | + await stagehand.context.pages()[0].goto("https://example.com"); |
| 63 | + |
| 64 | + // Make an act() call that will use the LLM |
| 65 | + await stagehand.act("find the heading on the page"); |
| 66 | + |
| 67 | + console.log("\n=== Test Results ==="); |
| 68 | + if (fetchCallCount > 0) { |
| 69 | + console.log(`✅ SUCCESS: Custom fetch was called ${fetchCallCount} times`); |
| 70 | + console.log(`✅ Custom headers detected: ${customHeaders.length > 0 ? customHeaders.join(", ") : "None (may be overridden by SDK)"}`); |
| 71 | + } else { |
| 72 | + console.log("❌ FAILURE: Custom fetch was NOT called"); |
| 73 | + console.log(" This indicates the bug still exists."); |
| 74 | + } |
| 75 | + } catch (error) { |
| 76 | + console.error("\n❌ Error during test:", error); |
| 77 | + } finally { |
| 78 | + await stagehand.close(); |
| 79 | + } |
| 80 | +} |
| 81 | + |
| 82 | +main().catch(console.error); |
0 commit comments