/** * Streaming helpers for `dsh-connect`. * @module dsh-connect/stream */ import type { SessionEvent } from "@deepseek-ai/dsh-session"; import type { TurnOutcome, TurnReason } from "./types.js"; import type { AsyncQueue } from "./types.js"; export declare function createAsyncQueue(): AsyncQueue; /** Per-turn streaming assembly state mutated by {@link applyStreamChunk}. */ export interface StreamState { chunks: { push(text: string): void; }; lastText: string; reasoning: boolean; hintPushed: boolean; lastIndex: number | undefined; pushedAny: boolean; lastPushAt: number; } /** * How much of the agent's live progress the streaming card shows. * - `full` — everything: reasoning text, tool calls, heartbeats, answer. * - `important` — key milestones only: thinking hint, tool calls, heartbeats, answer (no reasoning text). * - `result` — only the final answer (this is the default, keeping cards short). */ export type NotifyLevel = "full" | "important" | "result"; /** * Whether a level permits *continuous live status chatter* — the per-minute * "still processing" heartbeat and the periodic progress reminder. * * Only `full` does. The two quieter levels describe themselves in terms of * discrete events, not a running commentary: * - `important` — 「只推送关键节点:思考开始、工具调用、最终回答」 (three things) * - `result` — 「只在任务结束后发送最终结果」 (one thing) * A "still processing (3 min)" line every minute is not a milestone, so it * belongs to neither. This predicate exists so the answer is defined in one * place rather than as a `!== "result"` check repeated at each timer — which is * exactly how `important` came to receive heartbeat spam it never asked for. */ export declare function showsLiveStatus(level: NotifyLevel): boolean; /** One assistant chunk event of interest to the streaming bridge. */ export interface StreamChunkLike { type: string; index?: number; text?: string; block?: { type?: string; text?: string; }; } export declare function applyStreamChunk(state: StreamState, thinkingHint: string, chunk: StreamChunkLike, level?: NotifyLevel): void; /** * Push a localized tool-call status line into the streaming queue so long * tool-execution stretches stay visibly alive (the Web GUI shows tool calls; * the chat card should too). Ends the reasoning phase and drops the block * index so the next content block gets its own separator instead of stacking * one on top of the tool line's own blank lines. * @param state - the turn's mutable assembly state. * @param label - the localized status line, e.g. "🔧 调用工具 `pwsh` — …". */ export declare function applyToolCall(state: StreamState, label: string): void; /** Pull a short human summary out of a tool call's `arguments` JSON (whitespace folded to one line). */ export declare function toolCallSummary(argumentsJson: unknown): string | undefined; /** Pull the first question's text out of an `ask_user_question` arguments JSON (whitespace folded to one line). */ export declare function questionTextOf(argumentsJson: unknown): string; export declare function mapReason(kind: string): TurnReason; export declare function summarizeTurn(events: readonly SessionEvent[], firstSeq: number): TurnOutcome; export declare function truncate(text: string, max?: number): string; /** Error category used to pick actionable advice for the user. */ export type ErrorCategory = "permission" | "network" | "model" | "generic"; /** Classify an error message into an advice bucket (keyword-based, best-effort). */ export declare function classifyError(detail: string): ErrorCategory; /** Thousands-separated token count for display. */ export declare function fmtTokens(n: number): string; export declare function textOf(message: { content: readonly { type?: string; text?: string; }[]; } | undefined): string; //# sourceMappingURL=stream.d.ts.map