@mirasoth/soothe-client 0.2.1 → 0.4.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.ts CHANGED
@@ -167,7 +167,7 @@ declare const PROTO_VERSION = "1";
167
167
  /** Default client capabilities declared in the connection_init handshake. */
168
168
  declare const DEFAULT_CLIENT_CAPABILITIES: string[];
169
169
  /** Client version reported in the connection_init handshake. */
170
- declare const CLIENT_VERSION = "0.1.0";
170
+ declare const CLIENT_VERSION = "0.4.0";
171
171
  type MessageType = "connection_init" | "connection_ack" | "request" | "response" | "notification" | "subscribe" | "next" | "error" | "complete" | "unsubscribe" | "ping" | "pong" | "receipt_response" | "disconnect" | "status";
172
172
  /** Method names carried in the envelope `method` field (RFC-450 §9.2). */
173
173
  type MethodName = "loop_list" | "loop_get" | "loop_tree" | "loop_prune" | "loop_delete" | "loop_new" | "loop_reattach" | "loop_detach" | "loop_input" | "loop_messages" | "loop_state_get" | "loop_state_update" | "loop_cards_fetch" | "loop_history_fetch" | "loop_events" | "autopilot_events" | "job_create" | "job_status" | "job_pause" | "job_resume" | "job_cancel" | "job_dag" | "job_guidance" | "daemon_status" | "daemon_shutdown" | "config_get" | "config_reload" | "skills_list" | "invoke_skill" | "models_list" | "mcp_status" | "auth" | "auth_refresh" | "slash_command" | "rpc_command" | "delivery_ack" | "cron_add" | "cron_list" | "cron_show" | "cron_cancel" | "disconnect";
@@ -479,6 +479,9 @@ declare class Client extends EventEmitter {
479
479
  private config;
480
480
  private ws;
481
481
  private messageBuffer;
482
+ private inboundMaxSize;
483
+ private inboundDroppedCount;
484
+ private onStreamDegraded;
482
485
  private resolvers;
483
486
  private handshakeComplete;
484
487
  private negotiatedCapabilities;
@@ -489,6 +492,8 @@ declare class Client extends EventEmitter {
489
492
  private lastPongMonotonic;
490
493
  private disconnFired;
491
494
  private mux;
495
+ private deliveryRecvSeq;
496
+ private deliveryAckedSeq;
492
497
  constructor(url: string, config?: Config);
493
498
  /**
494
499
  * Dials the Soothe daemon WebSocket and completes the protocol-1 handshake
@@ -556,6 +561,21 @@ declare class Client extends EventEmitter {
556
561
  readEvent(): Promise<Record<string, unknown> | null>;
557
562
  /** Reads a single event with a timeout. Returns null on timeout or close. */
558
563
  readEventWithTimeout(timeout: number): Promise<Record<string, unknown> | null>;
564
+ /**
565
+ * Remove stale handshake/terminal frames left in `messageBuffer` before a turn.
566
+ * Returns labels of removed frames (in order).
567
+ */
568
+ peelStalePendingControlEvents(): string[];
569
+ /** True when the underlying socket is still open (may not be handshaked). */
570
+ isConnectionAlive(): boolean;
571
+ /** Override pending buffer cap (tests / tuning). */
572
+ setInboundMaxSize(n: number): void;
573
+ /** How many NORMAL-priority frames were dropped under backpressure. */
574
+ inboundDropped(): number;
575
+ /** Hook invoked on the first inbound overflow drop. */
576
+ setStreamDegradedCallback(fn: ((dropped: number, reason: string) => void) | null): void;
577
+ private enqueueMessageBuffer;
578
+ private noteInboundDrop;
559
579
  /**
560
580
  * Reads the next frame directly from the live socket (via a resolver),
561
581
  * bypassing `messageBuffer`. Used by RPC waits so that stream events
@@ -593,6 +613,8 @@ declare class Client extends EventEmitter {
593
613
  private _requestResponseForEnvelope;
594
614
  /** Sends a fire-and-forget `notification` envelope (no response expected). */
595
615
  notify(method: MethodName, params: Record<string, unknown>): Promise<void>;
616
+ private _trackInboundDeliveryAck;
617
+ private _sendDeliveryAck;
596
618
  /**
597
619
  * Starts a subscription stream. Returns the subscription `id` for later
598
620
  * correlation and `unsubscribe()`. Stream events arrive as `next` frames
@@ -710,82 +732,26 @@ declare class Client extends EventEmitter {
710
732
  }
711
733
 
712
734
  /**
713
- * Inbound-frame multiplexer for the protocol-1 client (RFC-629 constraint #1,
714
- * RFC-450 §5.2/§5.5).
715
- *
716
- * Routes inbound protocol-1 frames to the correct waiter by `(type, id)`
717
- * instead of discarding non-matching events. This makes the Client safe for
718
- * concurrent RPCs and lets an active subscription stream coexist with RPC
719
- * waits without starvation.
720
- *
721
- * Routing rules:
722
- * - `response`/`error` with `id` in pending RPCs → pending RPC waiter
723
- * - `next`/`complete` with `id` in pending subs → pending subscription waiter
724
- * - `receipt_response` with `receipt` in receipts → receipt waiter
725
- * - everything else → not consumed (flows to
726
- * the application event
727
- * stream / resolver queue)
728
- *
729
- * `ping`/`pong`/`connection_ack` are id-less lifecycle frames handled by the
730
- * Client before reaching the multiplexer; the multiplexer leaves them
731
- * un-consumed so the Client's existing handlers still see them.
732
- *
733
- * A frame routed to a waiter is consumed (returns `true`) and must NOT be
734
- * forwarded to the resolver queue / event stream.
735
- */
736
- /**
737
- * Multiplexer holds pending RPC, subscription, and receipt waiters keyed by
738
- * their correlation id. The Client consults `route()` for each inbound frame
739
- * before pushing it to the resolver queue.
735
+ * Ephemeral one-shot RPC client for jobs / cron / autopilot.
736
+ * Mirrors Python AsyncCommandClient / CommandClient (RFC-629 / IG-662).
740
737
  */
741
- declare class Multiplexer {
742
- private rpcs;
743
- private subs;
744
- private receipts;
745
- /**
746
- * Installs a pending RPC wait keyed by `id`. Returns the pending call and an
747
- * unregister function that MUST be called when the wait ends (success,
748
- * timeout, or cancel) to avoid leaks. If a late response arrives after the
749
- * caller has unregistered, it is dropped (log-and-drop) — no leak.
750
- */
751
- registerRPC(id: string): {
752
- call: Promise<Record<string, unknown>>;
753
- unregister: () => void;
754
- };
755
- /**
756
- * Installs a pending subscription stream keyed by `id`. Returns the stream
757
- * channel (an async-iterable-like push sink), a `done` signal, and an
758
- * unregister function. The Client pushes `next`/`complete` frames via
759
- * `push`; the application reads from the channel.
760
- */
761
- registerSubscription(id: string): {
762
- push: (frame: Record<string, unknown>) => void;
763
- done: Promise<void>;
764
- unregister: () => void;
765
- };
766
- /**
767
- * Installs a pending receipt wait keyed by `receipt`. Returns an unregister
768
- * function.
769
- */
770
- registerReceipt(receipt: string): {
771
- wait: Promise<Record<string, unknown>>;
772
- unregister: () => void;
773
- };
774
- /**
775
- * Wires a real sink for a registered subscription's `push`. Called by the
776
- * Client right after `registerSubscription` to install the channel/queue the
777
- * application reads from.
778
- */
779
- setSubscriptionSink(id: string, sink: (frame: Record<string, unknown>) => void): void;
780
- /**
781
- * Inspects one decoded frame, delivers it to a matching waiter if one
782
- * exists, and returns `true` (consumed). Returns `false` for frames with no
783
- * matching waiter — these flow on to the resolver queue / event stream.
784
- * Safe to call from the message handler.
785
- */
786
- route(frame: Record<string, unknown>): boolean;
787
- /** Reports whether an RPC waiter is registered for `id`. */
788
- hasRPCWaiter(id: string): boolean;
738
+
739
+ declare class CommandClient {
740
+ readonly url: string;
741
+ readonly timeoutMs: number;
742
+ private readonly config;
743
+ constructor(url: string, opts?: {
744
+ timeoutMs?: number;
745
+ config?: Config;
746
+ });
747
+ private withClient;
748
+ /** Generic one-shot RPC. */
749
+ request(method: MethodName, params?: Record<string, unknown>): Promise<Record<string, unknown>>;
750
+ jobCreate(goal: string, workspace?: string): Promise<Record<string, unknown>>;
751
+ jobStatus(jobId: string): Promise<Record<string, unknown>>;
752
+ jobCancel(jobId: string): Promise<Record<string, unknown>>;
753
+ cronAdd(text: string, priority?: number): Promise<Record<string, unknown>>;
754
+ cronList(status?: string): Promise<Record<string, unknown>>;
789
755
  }
790
756
 
791
757
  /**
@@ -810,6 +776,27 @@ declare function fetchLoopHistory(client: Client, loopID: string, timeout?: numb
810
776
  declare function authenticate(client: Client, accessKey: string, secretKey: string, timeout?: number): Promise<Record<string, unknown>>;
811
777
  /** Refreshes the daemon-side auth token and waits for the response. */
812
778
  declare function refreshAuthToken(client: Client, refreshToken: string, timeout?: number): Promise<Record<string, unknown>>;
779
+ /** Fetch bound display-card snapshot for a loop. */
780
+ declare function fetchLoopCards(client: Client, loopID: string, timeout?: number): Promise<Record<string, unknown>>;
781
+ /** Fetch persisted conversation/activity rows for a loop. */
782
+ declare function fetchLoopMessages(client: Client, loopID: string, opts?: {
783
+ limit?: number;
784
+ offset?: number;
785
+ includeEvents?: boolean;
786
+ timeout?: number;
787
+ }): Promise<Record<string, unknown>>;
788
+ /**
789
+ * Connect, handshake, and yield a ready Client. Always closes in finally.
790
+ */
791
+ declare function connectedWebsocket<T>(wsUrl: string, fn: (client: Client) => Promise<T>, timeoutMs?: number): Promise<T>;
792
+ /**
793
+ * One-shot protocol-1 RPC / notify / subscribe with dict-style error contract.
794
+ * Callers check `if ("error" in response)`.
795
+ */
796
+ declare function protocol1Rpc(wsUrl: string, method: string, params?: Record<string, unknown> | null, opts?: {
797
+ mode?: "request" | "notify" | "subscribe";
798
+ timeoutMs?: number;
799
+ }): Promise<Record<string, unknown>>;
813
800
 
814
801
  /**
815
802
  * loop_new (or reuse id) → subscribe(loop_events); returns the loop id.
@@ -828,6 +815,25 @@ declare function waitSubscriptionConfirmed(client: Client, wantLoopID: string, _
828
815
  /** Attempts to connect to the Soothe daemon with bounded retries. */
829
816
  declare function connectWithRetries(client: Client, maxRetries?: number, retryDelay?: number): Promise<void>;
830
817
 
818
+ /**
819
+ * Shared stream/turn terminal frame helpers for Client and DaemonSession.
820
+ *
821
+ * Keeps peel-at-turn-start and turn-end detection on one vocabulary so leftover
822
+ * prior-goal terminals cannot blank the next query.
823
+ */
824
+ /** Daemon turn-scoped stream end custom type. */
825
+ declare const STREAM_END = "soothe.stream.end";
826
+ /** True when `data` is a turn-scoped terminal custom payload. */
827
+ declare function isTurnEndCustomData(data: unknown): data is Record<string, unknown>;
828
+ /**
829
+ * True when a chunk proves the active turn has non-intake progress.
830
+ * Used so late prior-goal stream.end cannot close a turn that has only seen
831
+ * intake lifecycle (e.g. plan.phase).
832
+ */
833
+ declare function isTurnProgressChunk(mode: string, data: unknown): boolean;
834
+ /** True when the client should bump delivery_ack sequence for this frame. */
835
+ declare function inboundNeedsDeliveryAck(event: Record<string, unknown>): boolean;
836
+
831
837
  /**
832
838
  * Persistence seam for appkit (RFC-629 Layer 1).
833
839
  *
@@ -1004,12 +1010,19 @@ interface ClassifierConfig {
1004
1010
  minDeliverableRunes?: number;
1005
1011
  /** Optional app override of the default thinking-step event allowlist. */
1006
1012
  thinkingStepEvents?: ReadonlySet<string>;
1013
+ /**
1014
+ * When true, a status frame with state=idle and non-empty accumulated
1015
+ * assistant text is DeliverableComplete (typical for direct-model turns).
1016
+ * Default false keeps Continue-on-status behaviour.
1017
+ */
1018
+ treatStatusIdleAsComplete?: boolean;
1007
1019
  }
1008
1020
  /** Maps a stream of decoded daemon events into deliverable/streaming/terminal outcomes. */
1009
1021
  declare class EventClassifier {
1010
1022
  private deliverablePhases;
1011
1023
  private minDeliverableRunes;
1012
1024
  private thinkingStepEvents?;
1025
+ private treatStatusIdleAsComplete;
1013
1026
  constructor(cfg: ClassifierConfig);
1014
1027
  /**
1015
1028
  * Inspects one decoded event and returns its outcome. `accumulated` is the
@@ -1142,16 +1155,12 @@ interface ManagedClient {
1142
1155
  * (e.g. wrapping Client with logging/metrics).
1143
1156
  */
1144
1157
  type ClientFactory = (url: string, config?: Config) => ManagedClient;
1145
- /** Returns a ClientFactory that builds a core Client. */
1146
- declare function defaultClientFactory(): ClientFactory;
1147
1158
  /**
1148
1159
  * Creates a new loop (loop_new + subscribe) on a connected client and returns
1149
1160
  * the new loop id. The default implementation calls bootstrapLoopSession;
1150
1161
  * apps may override it.
1151
1162
  */
1152
1163
  type BootstrapFunc = (client: ManagedClient, workspaceID: string, userID: string, config?: Config) => Promise<string>;
1153
- /** Default bootstrap: loop_new + subscribe(loop_events). */
1154
- declare function defaultBootstrapFunc(): BootstrapFunc;
1155
1164
 
1156
1165
  /**
1157
1166
  * Per-session connection pool for appkit (RFC-629 Layer 1).
@@ -1178,7 +1187,8 @@ interface PoolConfig {
1178
1187
  maxIdleTime: number;
1179
1188
  healthCheckInterval: number;
1180
1189
  }
1181
- /** Returns env-overridable defaults (mirrors triarch). */
1190
+ /** Returns env-overridable defaults (mirrors triarch).
1191
+ * `maxIdleTime` is enforced on acquire; `healthCheckInterval` is reserved. */
1182
1192
  declare function defaultPoolConfig(): PoolConfig;
1183
1193
  /** One connection slot in the pool. */
1184
1194
  declare class PooledConn {
@@ -1246,6 +1256,29 @@ declare class ConnectionPool {
1246
1256
  private startReader;
1247
1257
  }
1248
1258
 
1259
+ /**
1260
+ * Attachment image compaction for appkit (Go IG-651 / SIL-04 parity).
1261
+ *
1262
+ * When `sharp` is installed (optionalDependency), oversized image/* payloads
1263
+ * are downscaled. Without sharp, attachments pass through unchanged.
1264
+ */
1265
+ interface CompactImageOptions {
1266
+ /** Max width or height in pixels. Default 768. */
1267
+ maxDim?: number;
1268
+ /** JPEG encode quality 1–100. Default 85. */
1269
+ jpegQuality?: number;
1270
+ }
1271
+ /**
1272
+ * Downscales image/* payloads when either dimension exceeds MaxDim.
1273
+ * Non-images and decode failures pass through unchanged.
1274
+ * PNG stays PNG; other image types re-encode as JPEG when sharp is available.
1275
+ */
1276
+ declare function compactImageAttachment(mimeType: string, dataB64: string, opts?: CompactImageOptions | null): Promise<[string, string]>;
1277
+ /**
1278
+ * Applies compactImageAttachment to each attachment map with mime_type + data.
1279
+ */
1280
+ declare function compactAttachments(atts: Record<string, unknown>[], opts?: CompactImageOptions | null): Promise<Record<string, unknown>[]>;
1281
+
1249
1282
  /**
1250
1283
  * Turn runner for appkit (RFC-629 Layer 1).
1251
1284
  *
@@ -1253,17 +1286,47 @@ declare class ConnectionPool {
1253
1286
  * single-flight, send loop_input, consume the event stream, classify events,
1254
1287
  * resolve the deliverable, persist the reply, and broadcast completion.
1255
1288
  *
1256
- * The app-agnostic successor to triarch's ExecuteQuery.
1289
+ * Supports IG-651 / SIL-04 lifecycle knobs: idle timeout, soft-complete
1290
+ * policies, attachment compaction, and stream-close soft-complete.
1257
1291
  */
1258
1292
 
1259
- /** Returned when a turn exceeds the configured timeout. */
1293
+ /** Returned when a turn exceeds the configured timeout and policy is Fail. */
1260
1294
  declare class ErrQueryTimeout extends Error {
1261
1295
  constructor();
1262
1296
  }
1297
+ /** Returned when no events arrive within IdleTimeout and policy is Fail. */
1298
+ declare class ErrIdleTimeout extends Error {
1299
+ constructor();
1300
+ }
1301
+ /** Selects fail vs soft-complete behaviour for idle, query, and stream-close. */
1302
+ declare enum TimeoutPolicy {
1303
+ Fail = 0,
1304
+ SoftComplete = 1
1305
+ }
1306
+ type StreamClosePolicy = TimeoutPolicy;
1307
+ declare const StreamCloseFail = TimeoutPolicy.Fail;
1308
+ declare const StreamCloseSoftComplete = TimeoutPolicy.SoftComplete;
1263
1309
  /** Configures a TurnRunner. */
1264
1310
  interface TurnConfig {
1265
1311
  /** Per-turn deadline in ms. Defaults to 30m. */
1266
1312
  queryTimeout: number;
1313
+ /** Max silence between classified events in ms. Zero disables (default). */
1314
+ idleTimeout?: number;
1315
+ /**
1316
+ * When > 0, raises idleTimeout for turns with attachments if idleTimeout
1317
+ * is positive but below this floor.
1318
+ */
1319
+ minIdleTimeoutWithAttachments?: number;
1320
+ /** Fail vs soft-complete when the idle watchdog fires. Default Fail. */
1321
+ onIdleTimeout?: TimeoutPolicy;
1322
+ /** Fail vs soft-complete when queryTimeout fires. Default Fail. */
1323
+ onQueryTimeout?: TimeoutPolicy;
1324
+ /** Fail vs soft-complete when the event stream closes. Default Fail. */
1325
+ onStreamClose?: StreamClosePolicy;
1326
+ /** Run compactAttachments before buildInput. Default false. */
1327
+ compactAttachmentsBeforeSend?: boolean;
1328
+ /** Overrides for compactAttachmentsBeforeSend. */
1329
+ compactImageOpts?: CompactImageOptions | null;
1267
1330
  }
1268
1331
  /** Carries optional daemon hints on a loop_input payload. */
1269
1332
  interface InputOpts {
@@ -1273,13 +1336,15 @@ interface InputOpts {
1273
1336
  responseSchemaName?: string;
1274
1337
  responseSchemaStrict?: boolean;
1275
1338
  }
1276
- /** Optional attachment shape (IG-327: {mime_type, data(base64)}). */
1339
+ /** Optional attachment shape ({mime_type, data(base64)}). */
1277
1340
  type Attachment = Record<string, unknown>;
1278
1341
  /**
1279
1342
  * Builds a loop_input payload with optional attachments. Apps build this from
1280
1343
  * their product modes (e.g. triarch's ask/agent/deep-research).
1281
1344
  */
1282
1345
  declare function inputMessageForLoop(text: string, loopID: string, attachments?: Attachment[], opts?: InputOpts): Record<string, unknown>;
1346
+ /** Effective idle timeout for a turn (attachment floor applied). */
1347
+ declare function idleTimeoutForTurn(cfg: TurnConfig, hasAttachments: boolean): number;
1283
1348
  /** Completion hook signature. */
1284
1349
  type OnComplete = (sessionID: string, loopID: string, content: string, completionEvent: string, elapsedMs: number) => void;
1285
1350
  /** Error hook signature. */
@@ -1297,25 +1362,13 @@ declare class TurnRunner {
1297
1362
  private buildInput;
1298
1363
  private onComplete;
1299
1364
  private onError;
1300
- /**
1301
- * Constructs a TurnRunner. pool, gate, classifier, and store are required;
1302
- * broadcaster may be null.
1303
- */
1304
1365
  constructor(pool: ConnectionPool, gate: QueryGate, classifier: EventClassifier, store: SessionStore, broadcaster: SSEBroadcaster | null, cfg: TurnConfig);
1305
- /** Overrides the loop_input payload builder. */
1306
1366
  withInputBuilder(f: typeof inputMessageForLoop): TurnRunner;
1307
- /** Sets a completion hook (runs inline on success). */
1308
1367
  withOnComplete(f: OnComplete): TurnRunner;
1309
- /** Sets an error hook (runs inline on failure). */
1310
1368
  withOnError(f: OnError): TurnRunner;
1311
- /**
1312
- * Runs one query turn. The response is broadcast via the SSE broadcaster and
1313
- * persisted via the SessionStore; it is not returned to the caller (SSE
1314
- * subscribers receive it). Resolves on success; rejects on failure
1315
- * (ErrQueryTimeout, AbortError, or a daemon/processing error).
1316
- */
1317
1369
  execute(sessionID: string, message: string, userID: string, workspaceID: string, attachments: Attachment[] | null, opts: InputOpts | null, signal?: AbortSignal): Promise<void>;
1318
- /** Asks the daemon to cooperatively stop the loop runner on a detached signal. */
1370
+ private finishTimeout;
1371
+ private completeTurn;
1319
1372
  private sendLoopCancel;
1320
1373
  private persistResponse;
1321
1374
  private persistFailed;
@@ -1324,4 +1377,120 @@ declare class TurnRunner {
1324
1377
  private broadcastError;
1325
1378
  }
1326
1379
 
1327
- export { type Attachment, type BaseEnvelope, type BootstrapFunc, CLIENT_VERSION, type ChatEventResult, ChatEventTerminal, type ClassifierConfig, Client, type ClientFactory, type CompleteEnvelope, type Config, type ConnectionAckEnvelope, ConnectionError, type ConnectionInitEnvelope, ConnectionPool, DEFAULT_CLIENT_CAPABILITIES, DEFAULT_DELIVERABLE_PHASES, DEFAULT_THINKING_STEP_EVENTS, DaemonError, type DecodedMessage, DisconnectCause, type DisconnectEnvelope, ErrPoolExhausted, ErrQueryBusy, ErrQueryTimeout, type ErrorEnvelope, EventAutopilotGoalCompleted, EventAutopilotGoalCreated, EventAutopilotGoalProgress, EventAutopilotGoalStatus, EventAutopilotWorkerAssigned, EventAutopilotWorkerUnassigned, EventCardCreated, EventCardReplayBegin, EventCardReplayEnd, EventClassifier, EventExploreCompleted, EventExploreMilestone, EventExploreStarted, EventExploreStepCompleted, EventFinalReport, EventGeneralFailed, EventLoopReattachedWire, EventMessageReceived, EventMessageSent, EventPlanCreated, EventReplayComplete, EventStrangeLoopCompleted, EventStrangeLoopContextCompacted, EventStrangeLoopPlanDecision, EventStrangeLoopReasoned, EventStrangeLoopStarted, EventStrangeLoopStepCompleted, EventStrangeLoopStepQueued, EventStrangeLoopStepStarted, EventStreamToolCallUpdate, EventTacitusCompleted, EventTacitusGatherSummary, EventTacitusStarted, EventToolCallUpdatesBatch, EventToolCompleted, EventToolError, EventToolStarted, INTENT_HINT_EMBED, INTENT_HINT_IMAGE_TO_TEXT, INTENT_HINT_OCR, INTENT_HINT_TEXT_COMPLETION, type InputOptions, type InputOpts, type IntentHint, LOOP_ASSISTANT_OUTPUT_PHASES, type LoopAssistantOutputPhase, type LoopInputIntentHint, type LoopInputParams, type LoopNewOptions, type ManagedClient, type MessageType, type MethodName, Multiplexer, type NegotiatedCapabilities, type NextEnvelope, type NotificationEnvelope, type OnComplete, type OnError, PROTO_VERSION, type PingEnvelope, type PongEnvelope, type PoolConfig, PooledConn, QueryGate, REMOVED_INTENT_HINTS, type ReceiptResponseEnvelope, ReconnectError, type RemovedIntentHint, type RequestEnvelope, type ResponseEnvelope, SSEBroadcaster, type SSEEvent, type SessionEntry, type SessionMessage, type SessionStore, StaleLoopError, type StatusFrame, type StreamEventPayload, type SubscribeEnvelope, TimeoutError, type TurnConfig, TurnRunner, type UnsubscribeEnvelope, type VerbosityLevel, VerbosityTier, authenticate, bootstrapLoopSession, checkDaemonStatus, classifyEventVerbosity, connectWithRetries, connectionInitEnvelope, decodeMessage, defaultBootstrapFunc, defaultClientFactory, defaultConfig, defaultPoolConfig, disconnectCauseName, disconnectEnvelope, encodeMessage, extractSootheLoopID, extractThinkingStep, fetchConfigSection, fetchLoopHistory, fetchSkillsCatalog, inputMessageForLoop, isCompletionEvent, isDaemonLive, isSubagentProgressEvent, isValidVerbosityLevel, loadConfigFromEnv, newLoopInputMessage, newLoopNewMessage, newLoopSubscribeMessage, newRequestID, notificationEnvelope, parseNamespace, pingEnvelope, pongEnvelope, refreshAuthToken, requestDaemonConfigReload, requestDaemonShutdown, requestEnvelope, shouldShow, splitWirePayload, subscribeEnvelope, unsubscribeEnvelope, validateLoopInputIntentHint, waitDaemonReady, waitLoopStatusWithID, waitSubscriptionConfirmed };
1380
+ /**
1381
+ * Per-turn observability counters for daemon stream consumption.
1382
+ */
1383
+ declare class TurnEventStats {
1384
+ total: number;
1385
+ messages: number;
1386
+ updates: number;
1387
+ custom: number;
1388
+ skipped: number;
1389
+ filteredEarly: number;
1390
+ toolCalls: number;
1391
+ toolResults: number;
1392
+ textChunks: number;
1393
+ heartbeatsDropped: number;
1394
+ postIdleDrained: number;
1395
+ inboundDropped: number;
1396
+ }
1397
+
1398
+ /**
1399
+ * Dual-socket daemon loop session with turn streaming (Python DaemonSession parity).
1400
+ *
1401
+ * Owns a subscribed stream WebSocket plus an RPC sidecar so metadata calls do not
1402
+ * starve loop events. `iterTurnChunks` handles idle timeout, post-idle drain,
1403
+ * loop scoping, and connection-loss detection.
1404
+ */
1405
+
1406
+ declare const DEFAULT_POST_IDLE_DRAIN_MS = 500;
1407
+ type EarlyDropFn = (namespace: unknown[], mode: string, data: unknown) => boolean;
1408
+ type StatsFactory = () => TurnEventStats;
1409
+ type StreamDeliveryResolver = () => string;
1410
+ interface DaemonSessionOptions {
1411
+ workspace?: string | null;
1412
+ streamDelivery?: string | StreamDeliveryResolver;
1413
+ postIdleDrainDeadlineMs?: number;
1414
+ earlyDropFn?: EarlyDropFn | null;
1415
+ statsFactory?: StatsFactory | null;
1416
+ config?: Config;
1417
+ }
1418
+ type TurnChunk = [namespace: unknown[], mode: string, data: unknown];
1419
+ /** Daemon-backed loop session with stream + RPC sockets. */
1420
+ declare class DaemonSession {
1421
+ private wsUrl;
1422
+ private workspace;
1423
+ private streamDelivery;
1424
+ private client;
1425
+ private rpcClient;
1426
+ private loopId;
1427
+ private readBusy;
1428
+ private rpcBusy;
1429
+ private rpcConnected;
1430
+ private streaming;
1431
+ private postIdleDrainDeadlineMs;
1432
+ private closed;
1433
+ private earlyDropFn;
1434
+ private statsFactory;
1435
+ private config;
1436
+ turnEventStats: TurnEventStats;
1437
+ lastTurnEndState: string | null;
1438
+ lastTurnCancellationSeen: boolean;
1439
+ lastTurnErrorMessage: string | null;
1440
+ constructor(wsUrl: string, opts?: DaemonSessionOptions);
1441
+ get streamClient(): Client;
1442
+ get rpcSideClient(): Client;
1443
+ get activeLoopId(): string | null;
1444
+ private resolveStreamDeliveryMode;
1445
+ get streamDeliveryMode(): string;
1446
+ private shouldDrop;
1447
+ connect(resumeLoopId?: string | null): Promise<Record<string, unknown>>;
1448
+ private bootstrapLoop;
1449
+ newLoop(): Promise<Record<string, unknown>>;
1450
+ switchLoop(loopId: string): Promise<Record<string, unknown>>;
1451
+ ensureConnected(): Promise<void>;
1452
+ close(): Promise<void>;
1453
+ detach(): Promise<void>;
1454
+ sendTurn(text: string, options?: {
1455
+ autonomous?: boolean;
1456
+ maxIterations?: number;
1457
+ preferredSubagent?: string;
1458
+ model?: string;
1459
+ modelParams?: Record<string, unknown>;
1460
+ attachments?: Array<{
1461
+ mime_type: string;
1462
+ data: string;
1463
+ }>;
1464
+ clarificationMode?: string;
1465
+ clarificationAnswer?: boolean;
1466
+ intentHint?: string;
1467
+ }): Promise<void>;
1468
+ cancelActiveTurn(): Promise<void>;
1469
+ private drainStreamEventsAfterIdle;
1470
+ private withRpcLock;
1471
+ private ensureRpcConnected;
1472
+ listLoops(_limit?: number): Promise<Record<string, unknown>>;
1473
+ fetchLoopCards(loopId: string): Promise<{
1474
+ cards: unknown[];
1475
+ seq: number;
1476
+ contextTokens: number;
1477
+ success: boolean;
1478
+ }>;
1479
+ fetchLoopHistory(loopId: string): Promise<{
1480
+ goals: unknown[];
1481
+ liveCards: unknown[];
1482
+ liveGoalIndex: number | null;
1483
+ contextTokens: number;
1484
+ success: boolean;
1485
+ }>;
1486
+ fetchConversationLog(loopId: string, opts?: {
1487
+ limit?: number;
1488
+ offset?: number;
1489
+ includeEvents?: boolean;
1490
+ }): Promise<Record<string, unknown>[]>;
1491
+ iterTurnChunks(opts?: {
1492
+ maxWaitMs?: number;
1493
+ }): AsyncGenerator<TurnChunk>;
1494
+ }
1495
+
1496
+ export { type Attachment, type BaseEnvelope, CLIENT_VERSION, type ChatEventResult, ChatEventTerminal, type ClassifierConfig, Client, CommandClient, type CompactImageOptions, type CompleteEnvelope, type Config, type ConnectionAckEnvelope, ConnectionError, type ConnectionInitEnvelope, ConnectionPool, DEFAULT_CLIENT_CAPABILITIES, DEFAULT_DELIVERABLE_PHASES, DEFAULT_POST_IDLE_DRAIN_MS, DEFAULT_THINKING_STEP_EVENTS, DaemonError, DaemonSession, type DaemonSessionOptions, type DecodedMessage, DisconnectCause, type DisconnectEnvelope, ErrIdleTimeout, ErrPoolExhausted, ErrQueryBusy, ErrQueryTimeout, type ErrorEnvelope, EventAutopilotGoalCompleted, EventAutopilotGoalCreated, EventAutopilotGoalProgress, EventAutopilotGoalStatus, EventAutopilotWorkerAssigned, EventAutopilotWorkerUnassigned, EventCardCreated, EventCardReplayBegin, EventCardReplayEnd, EventClassifier, EventExploreCompleted, EventExploreMilestone, EventExploreStarted, EventExploreStepCompleted, EventFinalReport, EventGeneralFailed, EventLoopReattachedWire, EventMessageReceived, EventMessageSent, EventPlanCreated, EventReplayComplete, EventStrangeLoopCompleted, EventStrangeLoopContextCompacted, EventStrangeLoopPlanDecision, EventStrangeLoopReasoned, EventStrangeLoopStarted, EventStrangeLoopStepCompleted, EventStrangeLoopStepQueued, EventStrangeLoopStepStarted, EventStreamToolCallUpdate, EventTacitusCompleted, EventTacitusGatherSummary, EventTacitusStarted, EventToolCallUpdatesBatch, EventToolCompleted, EventToolError, EventToolStarted, INTENT_HINT_EMBED, INTENT_HINT_IMAGE_TO_TEXT, INTENT_HINT_OCR, INTENT_HINT_TEXT_COMPLETION, type InputOptions, type InputOpts, type IntentHint, LOOP_ASSISTANT_OUTPUT_PHASES, type LoopAssistantOutputPhase, type LoopInputIntentHint, type LoopInputParams, type LoopNewOptions, type MessageType, type MethodName, type NegotiatedCapabilities, type NextEnvelope, type NotificationEnvelope, type OnComplete, type OnError, PROTO_VERSION, type PingEnvelope, type PongEnvelope, type PoolConfig, PooledConn, QueryGate, REMOVED_INTENT_HINTS, type ReceiptResponseEnvelope, ReconnectError, type RemovedIntentHint, type RequestEnvelope, type ResponseEnvelope, SSEBroadcaster, type SSEEvent, STREAM_END, type SessionEntry, type SessionMessage, type SessionStore, StaleLoopError, type StatusFrame, StreamCloseFail, type StreamClosePolicy, StreamCloseSoftComplete, type StreamEventPayload, type SubscribeEnvelope, TimeoutError, TimeoutPolicy, type TurnChunk, type TurnConfig, TurnEventStats, TurnRunner, type UnsubscribeEnvelope, type VerbosityLevel, VerbosityTier, authenticate, bootstrapLoopSession, checkDaemonStatus, classifyEventVerbosity, compactAttachments, compactImageAttachment, connectWithRetries, connectedWebsocket, connectionInitEnvelope, decodeMessage, defaultConfig, defaultPoolConfig, disconnectCauseName, disconnectEnvelope, encodeMessage, extractSootheLoopID, extractThinkingStep, fetchConfigSection, fetchLoopCards, fetchLoopHistory, fetchLoopMessages, fetchSkillsCatalog, idleTimeoutForTurn, inboundNeedsDeliveryAck, inputMessageForLoop, isCompletionEvent, isDaemonLive, isSubagentProgressEvent, isTurnEndCustomData, isTurnProgressChunk, isValidVerbosityLevel, loadConfigFromEnv, newLoopInputMessage, newLoopNewMessage, newLoopSubscribeMessage, newRequestID, notificationEnvelope, parseNamespace, pingEnvelope, pongEnvelope, protocol1Rpc, refreshAuthToken, requestDaemonConfigReload, requestDaemonShutdown, requestEnvelope, shouldShow, splitWirePayload, subscribeEnvelope, unsubscribeEnvelope, validateLoopInputIntentHint, waitDaemonReady, waitLoopStatusWithID, waitSubscriptionConfirmed };