Skip to content

stream/complete : façade d'entrée des appels LLM ​

源码版本v0.73.1

stream.ts est la couche la plus fine côté exposition de @mariozechner/pi-ai—quatre fonctions stream / complete / streamSimple / completeSimple, plus un resolveApiProvider interne. Elle ne fait pas d'analyse SSE, ne construit pas le corps de requête, ne gère pas les retries; elle route juste le triplet (model, context, options) vers le provider correspondant selon model.api. Tu peux la voir comme « le bureau de dispatch entre l'appelant et l'implémentation provider » : l'appelant ne voit qu'un type de retour unifié AssistantMessageEventStream, sans savoir si en dessous c'est du SSE Anthropic, des OpenAI Responses ou du Bedrock Converse.

Responsabilités ​

Cette couche fait quatre choses :

  1. Dispatch : stream trouve le provider dans le registre (registry) selon model.api et transfère (model, context, options). Voir packages/ai/src/stream.ts:25-32.
  2. Retour synchrone du flux : même si le provider sous-jacent s'initialise en async (lazy loading), stream retourne synchroniquement un AssistantMessageEventStream, et les événements sont pushés quand ils arrivent. Voir packages/ai/src/stream.ts:30-31.
  3. Entrée simplifiée : streamSimple / completeSimple prennent un SimpleStreamOptions (qui n'expose que reasoning, thinkingBudgets, etc., champs habituels côté UI), le provider traduit lui-même les simple options en options complètes. Voir packages/ai/src/stream.ts:43-50.
  4. Erreur si provider absent : resolveApiProvider jette No API provider registered for api: <api> si rien n'est enregistré, pas d'échec silencieux au point d'appel. Voir packages/ai/src/stream.ts:17-23.

Motivation de design ​

Pourquoi une couche aussi fine ? Parce que les deux choses qui intéressent l'appelant—« quel modèle appeler » et « streaming ou résultat final »—sont découplées du provider concret. stream.ts réduit ces deux dimensions à quatre fonctions; l'AgentSession de pi-coding-agent, les outils CLI et les extensions utilisent toutes la même entrée, sans avoir à importer directement le module provider. Ainsi l'implémentation provider peut être lazy-loadée, remplacée, ou étendue par de nouveaux api enregistrés par les extensions—le code appelant reste intact.

complete ne réécrit pas une logique non-streaming; il réutilise stream puis s.result()—l'infrastructure de streaming et le retour one-shot partagent le même pipeline, le provider n'a qu'à implémenter la version streaming.

Fichiers clés ​

Toute l'implémentation de stream tient en resolve + transfert, sans aucune logique métier :

typescript
// packages/ai/src/stream.ts:25-32
export function stream<TApi extends Api>(
	model: Model<TApi>,
	context: Context,
	options?: ProviderStreamOptions,
): AssistantMessageEventStream {
	const provider = resolveApiProvider(model.api);
	return provider.stream(model, context, options as StreamOptions);
}

complete réutilise stream puis prend result(), pas de duplication de la logique de dispatch :

typescript
// packages/ai/src/stream.ts:34-41
export async function complete<TApi extends Api>(
	model: Model<TApi>,
	context: Context,
	options?: ProviderStreamOptions,
): Promise<AssistantMessage> {
	const s = stream(model, context, options);
	return s.result();
}

Flux de données ​

La chaîne de dispatch de stream(model, ctx, opts) :

Frontières et échecs ​

  • Provider manquant : resolveApiProvider jette directement, ne renvoie pas de flux vide, voir packages/ai/src/stream.ts:19-21. Quand un provider enregistré dynamiquement par une extension n'est pas enregistré, l'appelant le sait immédiatement.
  • Provider lazy-loadé : le module provider concret est enveloppé par createLazyStream, stream retourne un outer stream synchro, puis une fois le module chargé, forwardStream vers l'inner, voir packages/ai/src/providers/register-builtins.ts:159-178. stream lui-même ne sait pas qu'il y a du lazy.
  • Assertion de type : options as StreamOptions caste ProviderStreamOptions (avec champs customs d'extension) vers le type attendu par le provider, qui lit les champs dont il a besoin.
  • options optionnel : les trois fonctions acceptent options? absent, le provider se rabat sur des valeurs par défaut.

Récapitulatif ​

stream.ts est une façade de dispatch de 60 lignes qui route (model, context, options) vers le provider du registre. stream / complete sont les versions toutes options, streamSimple / completeSimple sont les versions sous-ensemble adaptées à l'UI. La structure du registre (registry) elle-même se lit dans Registre des provider, l'enregistrement des 9 provider intégrés dans Abstraction provider et intégrations, et le AssistantMessageEventStream retourné dans Itérateur async EventStream.