import { StreamHelper } from "./stream-helpers.js";
import { StreamPart } from "../artifacts/ArtifactParser.js";
import { FullExecutionContext } from "@inkeep/agents-core";

//#region src/domains/run/stream/IncrementalStreamParser.d.ts

/**
 * Incremental parser that processes streaming text and structured-object deltas from Vercel AI
 * SDK generation and emits the right wire events to the client. Uses the unified ArtifactParser
 * to resolve artifact:ref / artifact:create markers.
 *
 * ---------------------------------------------------------------------------
 * Structured-output streaming pipeline (Anthropic + Output.object())
 * ---------------------------------------------------------------------------
 *
 * Upstream producer: `streamText({ output: Output.object({ schema }), ...,
 *   providerOptions: { anthropic: { structuredOutputMode: 'jsonTool' } } })`
 *
 * The Anthropic provider option is load-bearing. Without `structuredOutputMode: 'jsonTool'`,
 * newer Claude models (Sonnet 4.5, Opus 4.5, Opus 4.1) use Anthropic's native structured-outputs
 * beta which assembles the entire JSON response server-side and returns it as a single text
 * block at the end — producing ~20 seconds of silence followed by one giant text-delta event.
 * Forcing the synthetic-tool path restores token-by-token streaming via input_json_delta events.
 *
 * Consumer path (in stream-handler.ts): both `fullStream` (raw text-delta events containing
 * JSON tokens) and `partialOutputStream` (pre-parsed object deltas) are consumed in parallel
 * and both feed `processObjectDelta` here. They're deduped by length: `_doProcessObjectDelta`'s
 * Text branch only streams when currentText.length > previousTextContent.length.
 *
 * Wire-format mapping (what we emit vs what the model generated):
 *   - `{name: "Text", props: {text}}` components → streamed as text-delta wire events
 *     (via `streamHelper.streamText`). Their identity is flattened — the client sees plain
 *     text, not a data-component payload. We emit a '\n\n' separator when transitioning
 *     between distinct Text ids so consecutive Text blocks don't render as one run-on
 *     paragraph in Markdown.
 *   - Everything else (Card, Artifact, ArtifactCreate_*, etc.) → streamed as data-component
 *     wire events (via `streamHelper.writeData('data-component', data)`).
 *
 * Non-Text gating: we only emit a non-Text component when we have positional evidence that
 * the parser has moved past it — specifically, when a later component exists in the array.
 * Under fine-grained token streaming, a component frequently appears with empty/partial props
 * for one or more parses before filling in; the old snapshot-stability heuristic misfired on
 * these and produced empty `{}` or `{"id":""}` data-component events. The last visible
 * component is deferred to `finalize()` which runs after the stream closes.
 */
declare class IncrementalStreamParser {
  private buffer;
  private pendingTextBuffer;
  private streamHelper;
  private artifactParser;
  private hasStartedRole;
  private collectedParts;
  private contextId;
  private lastChunkWasToolResult;
  private componentAccumulator;
  private lastStreamedComponents;
  private componentSnapshots;
  private artifactMap?;
  private subAgentId?;
  private allStreamedContent;
  private writeQueue;
  private lastStreamedTextComponentId;
  private static readonly MAX_SNAPSHOT_SIZE;
  private static readonly MAX_STREAMED_SIZE;
  private static readonly MAX_COLLECTED_PARTS;
  constructor(streamHelper: StreamHelper, executionContext: FullExecutionContext, contextId: string, artifactParserOptions?: {
    sessionId?: string;
    taskId?: string;
    artifactComponents?: any[];
    streamRequestId?: string;
    subAgentId?: string;
    contextWindowSize?: number;
  });
  /**
   * Initialize artifact map for artifact:ref lookups during streaming
   * Should be called before processing chunks
   */
  initializeArtifactMap(): Promise<void>;
  /**
   * Mark that a tool result just completed, so next text should have spacing
   */
  markToolResult(): void;
  /**
   * Process a new text chunk for text streaming (handles artifact markers).
   * Writes are serialized via the internal writeQueue so concurrent callers
   * (fullStream + partialOutputStream) cannot corrupt shared state.
   */
  processTextChunk(chunk: string): Promise<void>;
  /**
   * Process object deltas directly from Vercel AI SDK's fullStream.
   * Writes are serialized via the internal writeQueue so concurrent callers
   * (fullStream + partialOutputStream) cannot corrupt shared state.
   */
  processObjectDelta(delta: any): Promise<void>;
  private _doProcessTextChunk;
  private _doProcessObjectDelta;
  /**
   * Emit any non-Text components that were present in earlier deltas but are no longer in the
   * current accumulator (e.g., the model replaced dataComponents between steps). Text components
   * are skipped because their content was already flushed to the client as text-delta events.
   */
  private flushEvictedComponents;
  /**
   * Stream the incremental text diff for a Text component. Under fine-grained token streaming
   * the component usually appears one or more times with empty props.text before any characters
   * land, so this method is a no-op until the text content actually grows.
   *
   * Emits a '\n\n' paragraph separator when transitioning between distinct Text ids so
   * consecutive Text blocks don't render as one run-on paragraph in Markdown. The separator
   * gate is `previousTextContent === ''` — the first time we stream any content for this id —
   * rather than "first time we see the component", because the component often appears with an
   * empty string value before the first token of text arrives.
   */
  private streamTextComponentDelta;
  /**
   * Write a text chunk to the client stream and record it in the collected/streamed buffers.
   */
  private emitTextToClient;
  /**
   * Store the latest JSON snapshot for a component id, evicting the oldest entry when the cap
   * is reached to bound memory.
   */
  private rememberSnapshot;
  /**
   * Stream a component and mark it as streamed
   * Note: Text components are handled separately with incremental streaming
   */
  private streamComponent;
  /**
   * Check if a component has the basic structure required for streaming
   * Requires id, name, and props object with content
   */
  private isComponentComplete;
  /**
   * Deep merge helper for object deltas
   */
  private deepMerge;
  /**
   * Legacy method for backward compatibility - defaults to text processing
   */
  processChunk(chunk: string): Promise<void>;
  /**
   * Process any remaining buffer content at the end of stream
   */
  finalize(): Promise<void>;
  /**
   * Get all collected parts for building the final response
   */
  getCollectedParts(): StreamPart[];
  /**
   * Get all streamed content that was actually sent to the user
   */
  getAllStreamedContent(): StreamPart[];
  /**
   * Parse buffer for complete artifacts and text parts (for text streaming)
   */
  private parseTextBuffer;
  /**
   * Check if text might be the start of an artifact marker
   */
  private mightBeArtifactStart;
  /**
   * Stream a formatted part (text or data) with smart buffering
   */
  private streamPart;
}
//#endregion
export { IncrementalStreamParser };