@astralform/js 7.1.1 → 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -822,7 +822,118 @@ interface StreamJobSSEOptions {
822
822
  headers: Record<string, string>;
823
823
  signal?: AbortSignal;
824
824
  fetchFn: typeof globalThis.fetch;
825
+ /** Request method; defaults to GET (the job event stream). */
826
+ method?: "GET" | "POST";
827
+ /** A JSON-serialised body for POST streams (the voice polish stream). */
828
+ body?: string;
825
829
  }
830
+ /**
831
+ * The styles a transcript can be shaped into, as the server names them.
832
+ * `raw` never calls the model — the transcript is used as recognized.
833
+ */
834
+ declare const VOICE_POLISH_MODES: readonly ["raw", "light", "structured", "formal"];
835
+ type VoicePolishMode = (typeof VOICE_POLISH_MODES)[number];
836
+ /** A mode that calls the polish model — every mode except `raw`. */
837
+ type VoiceLLMMode = Exclude<VoicePolishMode, "raw">;
838
+ /** Whether `value` is one of the four modes this SDK version knows. */
839
+ declare function isVoicePolishMode(value: unknown): value is VoicePolishMode;
840
+ /**
841
+ * Whether `mode` may be passed to `streamVoicePolish` — the check to make on
842
+ * `VoiceConfig.defaultMode`, which can be `raw`.
843
+ */
844
+ declare function isVoiceLLMMode(mode: VoicePolishMode): mode is VoiceLLMMode;
845
+ /**
846
+ * What a client needs to run the microphone for an agent, from
847
+ * `GET /v1/voice/config`. Deliberately carries no provider or model names.
848
+ */
849
+ interface VoiceConfig {
850
+ enabled: boolean;
851
+ /**
852
+ * The styles the client may request, as the server names them. Kept as
853
+ * plain strings so a mode this SDK version does not know still reaches a
854
+ * picker; `isVoicePolishMode` narrows one.
855
+ */
856
+ modes: string[];
857
+ /**
858
+ * The style to use when the user has not picked one. Falls back to
859
+ * `structured` when the server names a mode this SDK does not know. Can be
860
+ * `raw`, which `streamVoicePolish` refuses — check it with `isVoiceLLMMode`
861
+ * (or compare against `"raw"`) before polishing.
862
+ */
863
+ defaultMode: VoicePolishMode;
864
+ /** In tap-to-talk mode, the pause that ends a recording. */
865
+ silenceAutoStopSeconds: number;
866
+ /** Send the message as soon as the result is ready. */
867
+ autoSend: boolean;
868
+ maxRecordingSeconds: number;
869
+ /**
870
+ * Whether the configured recognizer emits live partial transcripts. Batch
871
+ * (Whisper-style) providers do not; they transcribe on stop.
872
+ */
873
+ supportsStreaming: boolean;
874
+ /**
875
+ * The project vocabulary, for display. The server applies it to every
876
+ * transcription and polish itself; `transcribeVoice({ hotwords })` and
877
+ * `VoicePolishRequest.hotwords` carry only the user's own words, which the
878
+ * server merges after these.
879
+ */
880
+ hotwords: string[];
881
+ }
882
+ /** One recording turned into text, from `POST /v1/voice/transcriptions`. */
883
+ interface VoiceTranscript {
884
+ text: string;
885
+ language: string | null;
886
+ /** Length of the submitted audio, when the WAV header said so. */
887
+ durationMs: number | null;
888
+ /** Time the provider took. */
889
+ asrMs: number;
890
+ }
891
+ interface VoiceTranscribeOptions {
892
+ /** File name sent with the recording; defaults to `recording.wav`. */
893
+ filename?: string;
894
+ /**
895
+ * The user's own vocabulary — not the project's, which the server already
896
+ * holds and merges in first. Sent comma-separated, so a word cannot itself
897
+ * contain a comma.
898
+ */
899
+ hotwords?: string[];
900
+ /** ISO 639-1 hint; omit for auto-detection. */
901
+ language?: string;
902
+ /**
903
+ * Abort the upload. No client-side deadline applies to this call (a
904
+ * recording can run to `maxRecordingSeconds` and the upload with it), so
905
+ * this is the only way to give up on a stalled one; the promise rejects
906
+ * with the abort reason (the runtime's `AbortError`, or what was passed to
907
+ * `abort(reason)`).
908
+ */
909
+ signal?: AbortSignal;
910
+ }
911
+ interface VoicePolishRequest {
912
+ text: string;
913
+ /** One of the LLM modes; `raw` is refused by the server. */
914
+ mode: VoiceLLMMode;
915
+ /** The user's own vocabulary; the server merges it after the project's. */
916
+ hotwords?: string[];
917
+ }
918
+ /**
919
+ * One frame of the polish stream. `delta` text arrives in order; `done.text`
920
+ * is authoritative (the cleaned full output, which can differ from the
921
+ * concatenated deltas). On `error` keep the raw transcript; `partial` is what
922
+ * was streamed before the failure.
923
+ */
924
+ type VoicePolishEvent = {
925
+ type: "delta";
926
+ text: string;
927
+ } | {
928
+ type: "done";
929
+ text: string;
930
+ polishMs: number;
931
+ } | {
932
+ type: "error";
933
+ reason: string;
934
+ partial: string;
935
+ detail?: string;
936
+ };
826
937
  interface ChatStreamEvent {
827
938
  event: string;
828
939
  data: string;
@@ -1087,6 +1198,34 @@ declare class AstralformClient {
1087
1198
  revokeToolPermission(id: string): Promise<void>;
1088
1199
  private mapAsset;
1089
1200
  uploadFile(conversationId: string, file: Blob, filename?: string): Promise<ConversationAsset>;
1201
+ /** The agent's voice-input defaults (`GET /v1/voice/config`). */
1202
+ getVoiceConfig(): Promise<VoiceConfig>;
1203
+ /**
1204
+ * Transcribe one recording with the agent's configured speech-to-text
1205
+ * provider (`POST /v1/voice/transcriptions`). 16 kHz mono 16-bit WAV is the
1206
+ * reference format; anything the provider accepts works.
1207
+ *
1208
+ * Deliberately outside `withDeadline`: a recording can run to
1209
+ * `VoiceConfig.maxRecordingSeconds`, so the 30 s default would cut real
1210
+ * uploads off. Pass `options.signal` to give up on a stalled one; the
1211
+ * promise then rejects with the abort reason — the runtime's `AbortError`,
1212
+ * or whatever was passed to `abort(reason)`.
1213
+ */
1214
+ transcribeVoice(audio: Blob, options?: VoiceTranscribeOptions): Promise<VoiceTranscript>;
1215
+ /**
1216
+ * Stream the LLM rewrite of a transcript (`POST /v1/voice/polish`) as typed
1217
+ * frames.
1218
+ *
1219
+ * Failures the server reports mid-stream arrive as an `error` frame, but
1220
+ * the iteration itself can reject: aborting `signal` closes the connection
1221
+ * (which cancels the model call upstream) and rejects with
1222
+ * `StreamAbortedError`; a non-2xx open rejects with `AuthenticationError`,
1223
+ * `RateLimitError` or `ServerError`; a network failure with
1224
+ * `ConnectionError`. Wrap the `for await` accordingly.
1225
+ */
1226
+ streamVoicePolish(request: VoicePolishRequest, options?: {
1227
+ signal?: AbortSignal;
1228
+ }): AsyncGenerator<VoicePolishEvent>;
1090
1229
  listUploads(conversationId: string): Promise<ConversationAsset[]>;
1091
1230
  listOutputs(conversationId: string): Promise<ConversationAsset[]>;
1092
1231
  listTeams(): Promise<TeamSummary[]>;
@@ -1104,6 +1243,14 @@ declare class AstralformClient {
1104
1243
  getActiveJob(conversationId: string): Promise<ActiveJob>;
1105
1244
  listJobs(conversationId: string): Promise<JobSummary[]>;
1106
1245
  }
1246
+ /**
1247
+ * Decode one SSE frame of `POST /v1/voice/polish`; null for frames the
1248
+ * client does not act on (pings, unknown events).
1249
+ */
1250
+ declare function parseVoicePolishFrame(frame: {
1251
+ event: string;
1252
+ data: string;
1253
+ }): VoicePolishEvent | null;
1107
1254
 
1108
1255
  /**
1109
1256
  * Minimal adapter contract. Frontends extend this with a `render()`
@@ -1532,7 +1679,8 @@ declare class StreamAbortedError extends AstralformError {
1532
1679
  declare function generateId(): string;
1533
1680
 
1534
1681
  /**
1535
- * GET-based SSE stream for job events.
1682
+ * SSE stream reader. GET for the job event stream (the default); POST with a
1683
+ * JSON body for the voice polish stream. The frame parser is the same.
1536
1684
  */
1537
1685
  declare function streamJobSSE(options: StreamJobSSEOptions): AsyncGenerator<ChatStreamEvent>;
1538
1686
 
@@ -1614,6 +1762,13 @@ declare class StreamManager {
1614
1762
  * its awaits. This can.
1615
1763
  */
1616
1764
  private turnCounter;
1765
+ /**
1766
+ * True while a `resync` is between its probe and its restore. Visibility and
1767
+ * focus listeners can both fire for one return, and two overlapping resyncs
1768
+ * would each detach the other's stream mid-flight — the second call must
1769
+ * find the flag set and leave the first to converge.
1770
+ */
1771
+ private _resyncing;
1617
1772
  constructor(session: ChatSession);
1618
1773
  get state(): StreamState;
1619
1774
  get activeConversationId(): string | null;
@@ -1645,6 +1800,38 @@ declare class StreamManager {
1645
1800
  switchTo(conversationId: string, opts?: {
1646
1801
  skipHistoryReplay?: boolean;
1647
1802
  }): Promise<void>;
1803
+ /**
1804
+ * Re-attach to whatever the server says is live for the ACTIVE conversation.
1805
+ *
1806
+ * The reconnect machinery inside ``consumeEventStream`` only runs while a
1807
+ * stream is being consumed — and a page suspended in the background (locked
1808
+ * phone, app switch, hidden tab) can outlive it: timers are throttled or
1809
+ * suspended, so the stall watchdog may never fire while hidden; the
1810
+ * reconnect budget (``SSE_MAX_RECONNECTS``) can burn out in fail-fast
1811
+ * attempts; and a 401 from a rotated access token ends the loop outright as
1812
+ * non-retryable. What is left is a manager that believes a turn is streaming
1813
+ * (or has given up on one that is still running) with nothing attached — and
1814
+ * no navigation will ever fix it, because ``switchTo`` early-returns on the
1815
+ * conversation it is already on.
1816
+ *
1817
+ * So the consumer calls this when the user COMES BACK
1818
+ * (``visibilitychange → visible``, window ``focus``). One ``getActiveJob``
1819
+ * probe, then:
1820
+ *
1821
+ * - attached to exactly the job the server calls live → healthy. The stall
1822
+ * watchdog owns zombie recovery from here, now that timers run again.
1823
+ * No-op.
1824
+ * - anything else — attached to a job the server no longer calls live,
1825
+ * attached to nothing while a job runs, or idle with a live job another
1826
+ * tab/device started — → detach and re-run ``restore``, the same path a
1827
+ * conversation reopen takes, with all of its supersession and takeover
1828
+ * guards inherited.
1829
+ *
1830
+ * Skipped while a restore is already in flight (it is converging on server
1831
+ * truth by itself) and while another resync holds the flag — see
1832
+ * ``_resyncing``.
1833
+ */
1834
+ resync(): Promise<void>;
1648
1835
  /**
1649
1836
  * Create a conversation and make it active.
1650
1837
  *
@@ -1816,4 +2003,4 @@ declare function isEmbeddedResource(value: unknown): value is {
1816
2003
  */
1817
2004
  declare function parseEmbeddedResource(value: unknown): EmbeddedResource | null;
1818
2005
 
1819
- export { type ActiveJob, type AgentCapability, type AgentIdentity, type AgentInfo, type AgentStatus, type AssetCreatedPayload, type AstralformApiKeyConfig, AstralformClient, type AstralformConfig, AstralformError, type AstralformUserTokenConfig, type AttachmentStagedPayload, AuthenticationError, type BlockDeltaPayload, CONVERSATION_PAGE_SIZE, type ChatEvent, ChatEventType, type ChatEventTypeValue, ChatSession, type ChatStorage, type ChatStreamEvent, type ChatStreamRequest, ConnectionError, type ContextUpdatePayload, type ContextWarningPayload, type Conversation, type ConversationAsset, type ConversationEvent, type DesktopStreamPayload, type EffortRung, type EmbeddedResource, type FeedbackRequest, type FeedbackResponse, InMemoryStorage, type JobCreateResponse, type JobStatus, type JobSummary, LLMNotConfiguredError, type MemoryRecallPayload, type MemoryRecord, type MemoryUpdatePayload, type Message, type ModelChoiceOptions, type ModelOption, type MyToolGrantsPage, type NoteUpdatePayload, type PlanUpdatePayload, type PromptSuggestionPayload, type ProtocolAdapter, ProtocolRegistry, RateLimitError, type RateLimitErrorDetails, type RawSseEvent, type ReasoningEffort, type SendOptions, ServerError, type SkillInfo, StreamAbortedError, type StreamJobSSEOptions, StreamManager, type StreamManagerEvent, type StreamState, type SubagentStartPayload, type SubagentStopPayload, type TaskStatus, type TeamAgentSummary, type TeamSummary, type ThinkingDescriptor, type ThinkingRungOption, type TitleGeneratedPayload, type TodoItem, type TodoUpdatePayload, type ToolApprovalDecision, type ToolApprovalGrantedPayload, type ToolApprovalRequest, type ToolApprovalRequestedPayload, type ToolApprovalScope, type ToolCallRequest, type ToolDefinition, type ToolGrant, type ToolHandler, type ToolHarnessWarningPayload, type ToolPermissionDeniedPayload, ToolRegistry, type ToolResult, type ToolResultRequest, type TurnUsage, type UIComponentsConfig, type UserUnavailablePayload, type WireBlockDelta, type WireBlockDeltaPayload, type WireBlockKind, type WireBlockStart, type WireBlockStatus, type WireBlockStop, type WireCustomEvent, type WireErrorEvent, type WireEvent, type WireInputArgDelta, type WireInputDelta, type WireKeepalive, type WireMessageStart, type WireMessageStop, type WireOutputDelta, type WireRetryEvent, type WireSignatureDelta, type WireStallWarning, type WireStatusDelta, type WireStopReason, type WireTextDelta, type WireThinkingDelta, type WorkspaceReadyPayload, generateId, isEmbeddedResource, mapSseToChat, parseEmbeddedResource, replayEvents, streamJobSSE, translateDelta };
2006
+ export { type ActiveJob, type AgentCapability, type AgentIdentity, type AgentInfo, type AgentStatus, type AssetCreatedPayload, type AstralformApiKeyConfig, AstralformClient, type AstralformConfig, AstralformError, type AstralformUserTokenConfig, type AttachmentStagedPayload, AuthenticationError, type BlockDeltaPayload, CONVERSATION_PAGE_SIZE, type ChatEvent, ChatEventType, type ChatEventTypeValue, ChatSession, type ChatStorage, type ChatStreamEvent, type ChatStreamRequest, ConnectionError, type ContextUpdatePayload, type ContextWarningPayload, type Conversation, type ConversationAsset, type ConversationEvent, type DesktopStreamPayload, type EffortRung, type EmbeddedResource, type FeedbackRequest, type FeedbackResponse, InMemoryStorage, type JobCreateResponse, type JobStatus, type JobSummary, LLMNotConfiguredError, type MemoryRecallPayload, type MemoryRecord, type MemoryUpdatePayload, type Message, type ModelChoiceOptions, type ModelOption, type MyToolGrantsPage, type NoteUpdatePayload, type PlanUpdatePayload, type PromptSuggestionPayload, type ProtocolAdapter, ProtocolRegistry, RateLimitError, type RateLimitErrorDetails, type RawSseEvent, type ReasoningEffort, type SendOptions, ServerError, type SkillInfo, StreamAbortedError, type StreamJobSSEOptions, StreamManager, type StreamManagerEvent, type StreamState, type SubagentStartPayload, type SubagentStopPayload, type TaskStatus, type TeamAgentSummary, type TeamSummary, type ThinkingDescriptor, type ThinkingRungOption, type TitleGeneratedPayload, type TodoItem, type TodoUpdatePayload, type ToolApprovalDecision, type ToolApprovalGrantedPayload, type ToolApprovalRequest, type ToolApprovalRequestedPayload, type ToolApprovalScope, type ToolCallRequest, type ToolDefinition, type ToolGrant, type ToolHandler, type ToolHarnessWarningPayload, type ToolPermissionDeniedPayload, ToolRegistry, type ToolResult, type ToolResultRequest, type TurnUsage, type UIComponentsConfig, type UserUnavailablePayload, VOICE_POLISH_MODES, type VoiceConfig, type VoiceLLMMode, type VoicePolishEvent, type VoicePolishMode, type VoicePolishRequest, type VoiceTranscribeOptions, type VoiceTranscript, type WireBlockDelta, type WireBlockDeltaPayload, type WireBlockKind, type WireBlockStart, type WireBlockStatus, type WireBlockStop, type WireCustomEvent, type WireErrorEvent, type WireEvent, type WireInputArgDelta, type WireInputDelta, type WireKeepalive, type WireMessageStart, type WireMessageStop, type WireOutputDelta, type WireRetryEvent, type WireSignatureDelta, type WireStallWarning, type WireStatusDelta, type WireStopReason, type WireTextDelta, type WireThinkingDelta, type WorkspaceReadyPayload, generateId, isEmbeddedResource, isVoiceLLMMode, isVoicePolishMode, mapSseToChat, parseEmbeddedResource, parseVoicePolishFrame, replayEvents, streamJobSSE, translateDelta };
package/dist/index.d.ts CHANGED
@@ -822,7 +822,118 @@ interface StreamJobSSEOptions {
822
822
  headers: Record<string, string>;
823
823
  signal?: AbortSignal;
824
824
  fetchFn: typeof globalThis.fetch;
825
+ /** Request method; defaults to GET (the job event stream). */
826
+ method?: "GET" | "POST";
827
+ /** A JSON-serialised body for POST streams (the voice polish stream). */
828
+ body?: string;
825
829
  }
830
+ /**
831
+ * The styles a transcript can be shaped into, as the server names them.
832
+ * `raw` never calls the model — the transcript is used as recognized.
833
+ */
834
+ declare const VOICE_POLISH_MODES: readonly ["raw", "light", "structured", "formal"];
835
+ type VoicePolishMode = (typeof VOICE_POLISH_MODES)[number];
836
+ /** A mode that calls the polish model — every mode except `raw`. */
837
+ type VoiceLLMMode = Exclude<VoicePolishMode, "raw">;
838
+ /** Whether `value` is one of the four modes this SDK version knows. */
839
+ declare function isVoicePolishMode(value: unknown): value is VoicePolishMode;
840
+ /**
841
+ * Whether `mode` may be passed to `streamVoicePolish` — the check to make on
842
+ * `VoiceConfig.defaultMode`, which can be `raw`.
843
+ */
844
+ declare function isVoiceLLMMode(mode: VoicePolishMode): mode is VoiceLLMMode;
845
+ /**
846
+ * What a client needs to run the microphone for an agent, from
847
+ * `GET /v1/voice/config`. Deliberately carries no provider or model names.
848
+ */
849
+ interface VoiceConfig {
850
+ enabled: boolean;
851
+ /**
852
+ * The styles the client may request, as the server names them. Kept as
853
+ * plain strings so a mode this SDK version does not know still reaches a
854
+ * picker; `isVoicePolishMode` narrows one.
855
+ */
856
+ modes: string[];
857
+ /**
858
+ * The style to use when the user has not picked one. Falls back to
859
+ * `structured` when the server names a mode this SDK does not know. Can be
860
+ * `raw`, which `streamVoicePolish` refuses — check it with `isVoiceLLMMode`
861
+ * (or compare against `"raw"`) before polishing.
862
+ */
863
+ defaultMode: VoicePolishMode;
864
+ /** In tap-to-talk mode, the pause that ends a recording. */
865
+ silenceAutoStopSeconds: number;
866
+ /** Send the message as soon as the result is ready. */
867
+ autoSend: boolean;
868
+ maxRecordingSeconds: number;
869
+ /**
870
+ * Whether the configured recognizer emits live partial transcripts. Batch
871
+ * (Whisper-style) providers do not; they transcribe on stop.
872
+ */
873
+ supportsStreaming: boolean;
874
+ /**
875
+ * The project vocabulary, for display. The server applies it to every
876
+ * transcription and polish itself; `transcribeVoice({ hotwords })` and
877
+ * `VoicePolishRequest.hotwords` carry only the user's own words, which the
878
+ * server merges after these.
879
+ */
880
+ hotwords: string[];
881
+ }
882
+ /** One recording turned into text, from `POST /v1/voice/transcriptions`. */
883
+ interface VoiceTranscript {
884
+ text: string;
885
+ language: string | null;
886
+ /** Length of the submitted audio, when the WAV header said so. */
887
+ durationMs: number | null;
888
+ /** Time the provider took. */
889
+ asrMs: number;
890
+ }
891
+ interface VoiceTranscribeOptions {
892
+ /** File name sent with the recording; defaults to `recording.wav`. */
893
+ filename?: string;
894
+ /**
895
+ * The user's own vocabulary — not the project's, which the server already
896
+ * holds and merges in first. Sent comma-separated, so a word cannot itself
897
+ * contain a comma.
898
+ */
899
+ hotwords?: string[];
900
+ /** ISO 639-1 hint; omit for auto-detection. */
901
+ language?: string;
902
+ /**
903
+ * Abort the upload. No client-side deadline applies to this call (a
904
+ * recording can run to `maxRecordingSeconds` and the upload with it), so
905
+ * this is the only way to give up on a stalled one; the promise rejects
906
+ * with the abort reason (the runtime's `AbortError`, or what was passed to
907
+ * `abort(reason)`).
908
+ */
909
+ signal?: AbortSignal;
910
+ }
911
+ interface VoicePolishRequest {
912
+ text: string;
913
+ /** One of the LLM modes; `raw` is refused by the server. */
914
+ mode: VoiceLLMMode;
915
+ /** The user's own vocabulary; the server merges it after the project's. */
916
+ hotwords?: string[];
917
+ }
918
+ /**
919
+ * One frame of the polish stream. `delta` text arrives in order; `done.text`
920
+ * is authoritative (the cleaned full output, which can differ from the
921
+ * concatenated deltas). On `error` keep the raw transcript; `partial` is what
922
+ * was streamed before the failure.
923
+ */
924
+ type VoicePolishEvent = {
925
+ type: "delta";
926
+ text: string;
927
+ } | {
928
+ type: "done";
929
+ text: string;
930
+ polishMs: number;
931
+ } | {
932
+ type: "error";
933
+ reason: string;
934
+ partial: string;
935
+ detail?: string;
936
+ };
826
937
  interface ChatStreamEvent {
827
938
  event: string;
828
939
  data: string;
@@ -1087,6 +1198,34 @@ declare class AstralformClient {
1087
1198
  revokeToolPermission(id: string): Promise<void>;
1088
1199
  private mapAsset;
1089
1200
  uploadFile(conversationId: string, file: Blob, filename?: string): Promise<ConversationAsset>;
1201
+ /** The agent's voice-input defaults (`GET /v1/voice/config`). */
1202
+ getVoiceConfig(): Promise<VoiceConfig>;
1203
+ /**
1204
+ * Transcribe one recording with the agent's configured speech-to-text
1205
+ * provider (`POST /v1/voice/transcriptions`). 16 kHz mono 16-bit WAV is the
1206
+ * reference format; anything the provider accepts works.
1207
+ *
1208
+ * Deliberately outside `withDeadline`: a recording can run to
1209
+ * `VoiceConfig.maxRecordingSeconds`, so the 30 s default would cut real
1210
+ * uploads off. Pass `options.signal` to give up on a stalled one; the
1211
+ * promise then rejects with the abort reason — the runtime's `AbortError`,
1212
+ * or whatever was passed to `abort(reason)`.
1213
+ */
1214
+ transcribeVoice(audio: Blob, options?: VoiceTranscribeOptions): Promise<VoiceTranscript>;
1215
+ /**
1216
+ * Stream the LLM rewrite of a transcript (`POST /v1/voice/polish`) as typed
1217
+ * frames.
1218
+ *
1219
+ * Failures the server reports mid-stream arrive as an `error` frame, but
1220
+ * the iteration itself can reject: aborting `signal` closes the connection
1221
+ * (which cancels the model call upstream) and rejects with
1222
+ * `StreamAbortedError`; a non-2xx open rejects with `AuthenticationError`,
1223
+ * `RateLimitError` or `ServerError`; a network failure with
1224
+ * `ConnectionError`. Wrap the `for await` accordingly.
1225
+ */
1226
+ streamVoicePolish(request: VoicePolishRequest, options?: {
1227
+ signal?: AbortSignal;
1228
+ }): AsyncGenerator<VoicePolishEvent>;
1090
1229
  listUploads(conversationId: string): Promise<ConversationAsset[]>;
1091
1230
  listOutputs(conversationId: string): Promise<ConversationAsset[]>;
1092
1231
  listTeams(): Promise<TeamSummary[]>;
@@ -1104,6 +1243,14 @@ declare class AstralformClient {
1104
1243
  getActiveJob(conversationId: string): Promise<ActiveJob>;
1105
1244
  listJobs(conversationId: string): Promise<JobSummary[]>;
1106
1245
  }
1246
+ /**
1247
+ * Decode one SSE frame of `POST /v1/voice/polish`; null for frames the
1248
+ * client does not act on (pings, unknown events).
1249
+ */
1250
+ declare function parseVoicePolishFrame(frame: {
1251
+ event: string;
1252
+ data: string;
1253
+ }): VoicePolishEvent | null;
1107
1254
 
1108
1255
  /**
1109
1256
  * Minimal adapter contract. Frontends extend this with a `render()`
@@ -1532,7 +1679,8 @@ declare class StreamAbortedError extends AstralformError {
1532
1679
  declare function generateId(): string;
1533
1680
 
1534
1681
  /**
1535
- * GET-based SSE stream for job events.
1682
+ * SSE stream reader. GET for the job event stream (the default); POST with a
1683
+ * JSON body for the voice polish stream. The frame parser is the same.
1536
1684
  */
1537
1685
  declare function streamJobSSE(options: StreamJobSSEOptions): AsyncGenerator<ChatStreamEvent>;
1538
1686
 
@@ -1614,6 +1762,13 @@ declare class StreamManager {
1614
1762
  * its awaits. This can.
1615
1763
  */
1616
1764
  private turnCounter;
1765
+ /**
1766
+ * True while a `resync` is between its probe and its restore. Visibility and
1767
+ * focus listeners can both fire for one return, and two overlapping resyncs
1768
+ * would each detach the other's stream mid-flight — the second call must
1769
+ * find the flag set and leave the first to converge.
1770
+ */
1771
+ private _resyncing;
1617
1772
  constructor(session: ChatSession);
1618
1773
  get state(): StreamState;
1619
1774
  get activeConversationId(): string | null;
@@ -1645,6 +1800,38 @@ declare class StreamManager {
1645
1800
  switchTo(conversationId: string, opts?: {
1646
1801
  skipHistoryReplay?: boolean;
1647
1802
  }): Promise<void>;
1803
+ /**
1804
+ * Re-attach to whatever the server says is live for the ACTIVE conversation.
1805
+ *
1806
+ * The reconnect machinery inside ``consumeEventStream`` only runs while a
1807
+ * stream is being consumed — and a page suspended in the background (locked
1808
+ * phone, app switch, hidden tab) can outlive it: timers are throttled or
1809
+ * suspended, so the stall watchdog may never fire while hidden; the
1810
+ * reconnect budget (``SSE_MAX_RECONNECTS``) can burn out in fail-fast
1811
+ * attempts; and a 401 from a rotated access token ends the loop outright as
1812
+ * non-retryable. What is left is a manager that believes a turn is streaming
1813
+ * (or has given up on one that is still running) with nothing attached — and
1814
+ * no navigation will ever fix it, because ``switchTo`` early-returns on the
1815
+ * conversation it is already on.
1816
+ *
1817
+ * So the consumer calls this when the user COMES BACK
1818
+ * (``visibilitychange → visible``, window ``focus``). One ``getActiveJob``
1819
+ * probe, then:
1820
+ *
1821
+ * - attached to exactly the job the server calls live → healthy. The stall
1822
+ * watchdog owns zombie recovery from here, now that timers run again.
1823
+ * No-op.
1824
+ * - anything else — attached to a job the server no longer calls live,
1825
+ * attached to nothing while a job runs, or idle with a live job another
1826
+ * tab/device started — → detach and re-run ``restore``, the same path a
1827
+ * conversation reopen takes, with all of its supersession and takeover
1828
+ * guards inherited.
1829
+ *
1830
+ * Skipped while a restore is already in flight (it is converging on server
1831
+ * truth by itself) and while another resync holds the flag — see
1832
+ * ``_resyncing``.
1833
+ */
1834
+ resync(): Promise<void>;
1648
1835
  /**
1649
1836
  * Create a conversation and make it active.
1650
1837
  *
@@ -1816,4 +2003,4 @@ declare function isEmbeddedResource(value: unknown): value is {
1816
2003
  */
1817
2004
  declare function parseEmbeddedResource(value: unknown): EmbeddedResource | null;
1818
2005
 
1819
- export { type ActiveJob, type AgentCapability, type AgentIdentity, type AgentInfo, type AgentStatus, type AssetCreatedPayload, type AstralformApiKeyConfig, AstralformClient, type AstralformConfig, AstralformError, type AstralformUserTokenConfig, type AttachmentStagedPayload, AuthenticationError, type BlockDeltaPayload, CONVERSATION_PAGE_SIZE, type ChatEvent, ChatEventType, type ChatEventTypeValue, ChatSession, type ChatStorage, type ChatStreamEvent, type ChatStreamRequest, ConnectionError, type ContextUpdatePayload, type ContextWarningPayload, type Conversation, type ConversationAsset, type ConversationEvent, type DesktopStreamPayload, type EffortRung, type EmbeddedResource, type FeedbackRequest, type FeedbackResponse, InMemoryStorage, type JobCreateResponse, type JobStatus, type JobSummary, LLMNotConfiguredError, type MemoryRecallPayload, type MemoryRecord, type MemoryUpdatePayload, type Message, type ModelChoiceOptions, type ModelOption, type MyToolGrantsPage, type NoteUpdatePayload, type PlanUpdatePayload, type PromptSuggestionPayload, type ProtocolAdapter, ProtocolRegistry, RateLimitError, type RateLimitErrorDetails, type RawSseEvent, type ReasoningEffort, type SendOptions, ServerError, type SkillInfo, StreamAbortedError, type StreamJobSSEOptions, StreamManager, type StreamManagerEvent, type StreamState, type SubagentStartPayload, type SubagentStopPayload, type TaskStatus, type TeamAgentSummary, type TeamSummary, type ThinkingDescriptor, type ThinkingRungOption, type TitleGeneratedPayload, type TodoItem, type TodoUpdatePayload, type ToolApprovalDecision, type ToolApprovalGrantedPayload, type ToolApprovalRequest, type ToolApprovalRequestedPayload, type ToolApprovalScope, type ToolCallRequest, type ToolDefinition, type ToolGrant, type ToolHandler, type ToolHarnessWarningPayload, type ToolPermissionDeniedPayload, ToolRegistry, type ToolResult, type ToolResultRequest, type TurnUsage, type UIComponentsConfig, type UserUnavailablePayload, type WireBlockDelta, type WireBlockDeltaPayload, type WireBlockKind, type WireBlockStart, type WireBlockStatus, type WireBlockStop, type WireCustomEvent, type WireErrorEvent, type WireEvent, type WireInputArgDelta, type WireInputDelta, type WireKeepalive, type WireMessageStart, type WireMessageStop, type WireOutputDelta, type WireRetryEvent, type WireSignatureDelta, type WireStallWarning, type WireStatusDelta, type WireStopReason, type WireTextDelta, type WireThinkingDelta, type WorkspaceReadyPayload, generateId, isEmbeddedResource, mapSseToChat, parseEmbeddedResource, replayEvents, streamJobSSE, translateDelta };
2006
+ export { type ActiveJob, type AgentCapability, type AgentIdentity, type AgentInfo, type AgentStatus, type AssetCreatedPayload, type AstralformApiKeyConfig, AstralformClient, type AstralformConfig, AstralformError, type AstralformUserTokenConfig, type AttachmentStagedPayload, AuthenticationError, type BlockDeltaPayload, CONVERSATION_PAGE_SIZE, type ChatEvent, ChatEventType, type ChatEventTypeValue, ChatSession, type ChatStorage, type ChatStreamEvent, type ChatStreamRequest, ConnectionError, type ContextUpdatePayload, type ContextWarningPayload, type Conversation, type ConversationAsset, type ConversationEvent, type DesktopStreamPayload, type EffortRung, type EmbeddedResource, type FeedbackRequest, type FeedbackResponse, InMemoryStorage, type JobCreateResponse, type JobStatus, type JobSummary, LLMNotConfiguredError, type MemoryRecallPayload, type MemoryRecord, type MemoryUpdatePayload, type Message, type ModelChoiceOptions, type ModelOption, type MyToolGrantsPage, type NoteUpdatePayload, type PlanUpdatePayload, type PromptSuggestionPayload, type ProtocolAdapter, ProtocolRegistry, RateLimitError, type RateLimitErrorDetails, type RawSseEvent, type ReasoningEffort, type SendOptions, ServerError, type SkillInfo, StreamAbortedError, type StreamJobSSEOptions, StreamManager, type StreamManagerEvent, type StreamState, type SubagentStartPayload, type SubagentStopPayload, type TaskStatus, type TeamAgentSummary, type TeamSummary, type ThinkingDescriptor, type ThinkingRungOption, type TitleGeneratedPayload, type TodoItem, type TodoUpdatePayload, type ToolApprovalDecision, type ToolApprovalGrantedPayload, type ToolApprovalRequest, type ToolApprovalRequestedPayload, type ToolApprovalScope, type ToolCallRequest, type ToolDefinition, type ToolGrant, type ToolHandler, type ToolHarnessWarningPayload, type ToolPermissionDeniedPayload, ToolRegistry, type ToolResult, type ToolResultRequest, type TurnUsage, type UIComponentsConfig, type UserUnavailablePayload, VOICE_POLISH_MODES, type VoiceConfig, type VoiceLLMMode, type VoicePolishEvent, type VoicePolishMode, type VoicePolishRequest, type VoiceTranscribeOptions, type VoiceTranscript, type WireBlockDelta, type WireBlockDeltaPayload, type WireBlockKind, type WireBlockStart, type WireBlockStatus, type WireBlockStop, type WireCustomEvent, type WireErrorEvent, type WireEvent, type WireInputArgDelta, type WireInputDelta, type WireKeepalive, type WireMessageStart, type WireMessageStop, type WireOutputDelta, type WireRetryEvent, type WireSignatureDelta, type WireStallWarning, type WireStatusDelta, type WireStopReason, type WireTextDelta, type WireThinkingDelta, type WorkspaceReadyPayload, generateId, isEmbeddedResource, isVoiceLLMMode, isVoicePolishMode, mapSseToChat, parseEmbeddedResource, parseVoicePolishFrame, replayEvents, streamJobSSE, translateDelta };