(
url: string | (() => string),
options:
| FetchConnectionOptions
| (() => FetchConnectionOptions | Promise<FetchConnectionOptions>) = {},
)
| 572 | * ``` |
| 573 | */ |
| 574 | export function fetchHttpStream( |
| 575 | url: string | (() => string), |
| 576 | options: |
| 577 | | FetchConnectionOptions |
| 578 | | (() => FetchConnectionOptions | Promise<FetchConnectionOptions>) = {}, |
| 579 | ): ConnectConnectionAdapter { |
| 580 | return { |
| 581 | async *connect(messages, data, abortSignal, runContext) { |
| 582 | // Resolve URL and options if they are functions |
| 583 | const resolvedUrl = typeof url === 'function' ? url() : url |
| 584 | const resolvedOptions = |
| 585 | typeof options === 'function' ? await options() : options |
| 586 | |
| 587 | const requestHeaders: Record<string, string> = { |
| 588 | 'Content-Type': 'application/json', |
| 589 | ...mergeHeaders(resolvedOptions.headers), |
| 590 | } |
| 591 | |
| 592 | // Build AG-UI RunAgentInput payload. |
| 593 | // |
| 594 | // Precedence (later spreads win): static adapter `body` is the base, |
| 595 | // overridden by `runContext.forwardedProps` (constructor body / |
| 596 | // forwardedProps options), overridden by per-message `data` passed |
| 597 | // to `connection.send`. Runtime values win over static config — |
| 598 | // this matches the documented "forwardedProps wins" semantic. |
| 599 | const requestBody = buildRunAgentInputBody( |
| 600 | messages, |
| 601 | data, |
| 602 | runContext, |
| 603 | resolvedOptions, |
| 604 | ) |
| 605 | |
| 606 | const fetchClient = resolvedOptions.fetchClient ?? fetch |
| 607 | // `RequestInit.signal` is typed `AbortSignal | null` (no `undefined` |
| 608 | // under `exactOptionalPropertyTypes`), so spread it conditionally |
| 609 | // rather than passing `undefined` explicitly. |
| 610 | const signal = abortSignal || resolvedOptions.signal |
| 611 | const response = await fetchClient(resolvedUrl, { |
| 612 | method: 'POST', |
| 613 | headers: requestHeaders, |
| 614 | body: JSON.stringify(requestBody), |
| 615 | credentials: resolvedOptions.credentials || 'same-origin', |
| 616 | ...(signal ? { signal } : {}), |
| 617 | }) |
| 618 | |
| 619 | if (!response.ok) { |
| 620 | throw new Error( |
| 621 | `HTTP error! status: ${response.status} ${response.statusText}`, |
| 622 | ) |
| 623 | } |
| 624 | |
| 625 | // Parse raw HTTP stream (newline-delimited JSON) |
| 626 | const reader = getResponseStreamReader(response) |
| 627 | |
| 628 | for await (const line of readStreamLines(reader, abortSignal)) { |
| 629 | yield JSON.parse(line) as StreamChunk |
| 630 | } |
| 631 | }, |
no outgoing calls
no test coverage detected