@juspay/neurolink
Version:
The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002
68 lines (67 loc) • 3.58 kB
TypeScript
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, anthropic) 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;