@oh-my-pi/pi-ai 18.2.2 → 18.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/stream.ts CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  } from "@oh-my-pi/pi-catalog/model-thinking";
16
16
  import { providerEntries } from "@oh-my-pi/pi-catalog/compat/providers";
17
17
  import { CODEX_BASE_URL } from "@oh-my-pi/pi-catalog/wire/codex";
18
- import { $env, $pickenv, getProviderInFlightRoot, isEnoent, logger } from "@oh-my-pi/pi-utils";
18
+ import { $env, $pickenv, getProviderInFlightRoot, isEnoent, logger, untilAborted } from "@oh-my-pi/pi-utils";
19
19
  import { getCustomApi } from "./api-registry";
20
20
  import { createAuthRetryKeyState, isApiKeyResolver, resolveNextAuthRetryKey } from "./auth-retry";
21
21
  import * as AIError from "./error";
@@ -889,11 +889,40 @@ export function listProvidersWithEnvKey(): string[] {
889
889
  return Object.keys(serviceProviderMap);
890
890
  }
891
891
 
892
+ function withResolvedModelHeaders<TApi extends Api>(
893
+ model: Model<TApi>,
894
+ signal: AbortSignal | undefined,
895
+ run: (resolvedModel: Model<TApi>) => AssistantMessageEventStream,
896
+ ): AssistantMessageEventStream {
897
+ const resolveHeaders = model.resolveHeaders;
898
+ if (!resolveHeaders) return run(model);
899
+
900
+ const outer = new AssistantMessageEventStream();
901
+ void (async () => {
902
+ try {
903
+ const headers = await untilAborted(signal, () => resolveHeaders(signal));
904
+ signal?.throwIfAborted();
905
+ const inner = run({ ...model, resolveHeaders: undefined, headers: headers ? { ...headers } : undefined });
906
+ for await (const event of inner) {
907
+ outer.push(event);
908
+ if (outer.done) return;
909
+ }
910
+ if (!outer.done) outer.end(await inner.result());
911
+ } catch (error) {
912
+ outer.fail(error);
913
+ }
914
+ })();
915
+ return outer;
916
+ }
917
+
892
918
  export function stream<TApi extends Api>(
893
919
  model: Model<TApi>,
894
920
  context: Context,
895
921
  options?: OptionsForApi<TApi>,
896
922
  ): AssistantMessageEventStream {
923
+ if (model.resolveHeaders) {
924
+ return withResolvedModelHeaders(model, options?.signal, resolvedModel => stream(resolvedModel, context, options));
925
+ }
897
926
  if (!model.requiresGlyphTokenization) {
898
927
  return withThinkingLoopGuard(model, options, opts =>
899
928
  withProviderInFlightLimit(model, opts, () => streamDispatch(model, context, opts)),
@@ -1623,6 +1652,12 @@ function streamSimpleRequest<TApi extends Api>(
1623
1652
  return outer;
1624
1653
  }
1625
1654
 
1655
+ if (model.resolveHeaders) {
1656
+ return withResolvedModelHeaders(model, requestOptions.signal, resolvedModel =>
1657
+ streamSimpleRequest(resolvedModel, context, requestOptions),
1658
+ );
1659
+ }
1660
+
1626
1661
  // Pi-native transport short-circuits the per-provider dispatch entirely:
1627
1662
  // the gateway resolves provider + credential server-side, so we don't
1628
1663
  // need an `apiKey` from `getEnvApiKey` here — `options.apiKey` carries