@juspay/neurolink
Version:
Universal AI Development Platform with working MCP integration, multi-provider support, voice (TTS/STT/realtime), and professional CLI. 58+ external MCP servers discoverable, multimodal file processing, RAG pipelines. Build, test, and deploy AI applicatio
81 lines (80 loc) • 4.3 kB
TypeScript
/**
* Curator P3-6: shared builder for the `NoOutputGeneratedError` sentinel
* chunk. Each provider's stream-transformation generator catches the AI
* SDK's `NoOutputGeneratedError` and yields this sentinel so downstream
* telemetry has finish reason + token usage + provider error context
* instead of just `{ noOutput: true, errorType: "..." }`.
*
* The AI SDK rejects `result.finishReason` / `result.totalUsage` in this
* branch today (see `ai/src/generate-text/stream-text.ts` ~L1078); we
* still attempt to await them so a future SDK version surfacing partial
* values populates the sentinel automatically. When they reject we keep
* conservative defaults (`finishReason: "error"`, zero usage).
*/
import type { StreamNoOutputSentinel, StreamNoOutputSentinelResultLike } from "../types/index.js";
export declare function buildNoOutputSentinel(error: unknown, result?: StreamNoOutputSentinelResultLike,
/**
* Reviewer follow-up: AI SDK v6 wraps the AI SDK's
* `NoOutputGeneratedError` without preserving the underlying provider
* error in `error.cause`, and rejects `result.finishReason` /
* `result.totalUsage` with the wrapped error too. To differentiate
* content-filter / stop-sequence / provider-crash, providers can
* capture the upstream error (e.g. via streamText's `onError`
* callback) and pass it here. When provided, it takes precedence
* over the AI SDK error for `providerError` and `modelResponseRaw`.
*/
underlyingError?: unknown): Promise<StreamNoOutputSentinel>;
/**
* Curator P3-6 (round-2): the AI SDK v6 path that sets
* `NoOutputGeneratedError` does NOT throw it from `result.textStream`
* iteration — it sets the error as a *promise rejection* on
* `result.finishReason` / `result.totalUsage` / `result.steps` (see
* `ai/src/generate-text/stream-text.ts` ~L1078). Providers that only
* catch errors thrown from `for await (chunk of result.textStream)` will
* miss the production trigger entirely: the stream completes silently
* with 0 chunks and the rejection bubbles as an unhandled rejection.
*
* This helper surfaces the rejection by awaiting `result.finishReason`
* after the stream completes. Providers must call this AFTER iterating
* the textStream when 0 chunks were yielded — the returned sentinel
* (if non-null) carries the enriched metadata Curator's report needed.
*/
export declare function detectPostStreamNoOutput(result: StreamNoOutputSentinelResultLike,
/**
* Optional provider-captured underlying error (e.g. from streamText's
* `onError` callback). When provided, the resulting sentinel will carry
* the real provider error in `providerError` / `modelResponseRaw`
* instead of the AI SDK's generic "No output generated" message.
*/
underlyingError?: unknown): Promise<{
sentinel: StreamNoOutputSentinel;
error: Error;
} | null>;
/**
* Reviewer follow-up: every provider's post-stream NoOutput detect must
* stamp the active OTel span so Pipeline B (`ContextEnricher.onEnd()` →
* `applyNonErrorLangfuseLevel`) surfaces a WARNING-level Langfuse
* observation with the enriched status message. Without this, only
* `StreamHandler`-based providers produced the rich telemetry; the
* provider-specific paths (openAI, openaiCompatible, litellm,
* huggingFace, openRouter, anthropicBaseProvider) yielded the sentinel
* to direct stream consumers but Pipeline B saw nothing.
*
* Stamps three attributes:
* - `neurolink.no_output = true` (Pipeline B trigger)
* - `langfuse.status_message` (enriched, with finishReason + tokens)
* - `neurolink.no_output.finish_reason` (raw finish reason)
*
* Safe to call when tracing isn't initialized — silently no-ops.
*/
export declare function stampNoOutputSpan(sentinel: StreamNoOutputSentinel): void;
/**
* Build the OTel `langfuse.status_message` summary string for a no-output
* stream. Used by `StreamHandler.createTextStream` and any future provider
* that wants to stamp the active span with the same enriched message.
*
* Reviewer follow-up: AI SDK v4 used `promptTokens` / `completionTokens`,
* v6 uses `inputTokens` / `outputTokens`. Read both shapes so the message
* is correct whichever version surfaced partial usage data.
*/
export declare function buildNoOutputStatusMessage(finishReason: unknown, usage: unknown): string;