@mirasoth/soothe-client 0.2.1 → 0.4.1

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
@@ -1,7 +1,7 @@
1
1
  import { EventEmitter } from 'node:events';
2
2
 
3
3
  /**
4
- * Custom error types for the Soothe client (RFC-450 protocol-1).
4
+ * Custom error types for the Soothe client.
5
5
  */
6
6
  /** Represents a WebSocket connection failure. */
7
7
  declare class ConnectionError extends Error {
@@ -11,13 +11,13 @@ declare class ConnectionError extends Error {
11
11
  constructor(url: string, attempt: number, cause: Error);
12
12
  }
13
13
  /**
14
- * Represents an error reported by the Soothe daemon (RFC-450 §7).
14
+ * Represents an error reported by the Soothe daemon.
15
15
  *
16
16
  * The daemon's structured error object carries a numeric `code` from the
17
17
  * reserved ranges, a human-readable `message`, and optional `data`.
18
18
  */
19
19
  declare class DaemonError extends Error {
20
- /** Numeric error code from the RFC-450 §7.3 registry. */
20
+ /** Numeric error code from the daemon error registry. */
21
21
  readonly code: number;
22
22
  /** The daemon's error message text. */
23
23
  readonly daemonMessage: string;
@@ -32,7 +32,7 @@ declare class TimeoutError extends Error {
32
32
  constructor(operation: string, duration: string);
33
33
  }
34
34
  /**
35
- * Distinguishes clean vs unclean connection loss (RFC-450 §4, §8.3).
35
+ * Distinguishes clean vs unclean connection loss.
36
36
  *
37
37
  * A clean drop follows a `disconnect` notification (loops keep running
38
38
  * server-side); an unclean drop is a read/write error or a missed pong
@@ -40,9 +40,9 @@ declare class TimeoutError extends Error {
40
40
  * event: the cause is emitted exactly once when the connection drops.
41
41
  */
42
42
  declare enum DisconnectCause {
43
- /** Abrupt loss: read/write error or missed pong (RFC-450 §8.3). */
43
+ /** Abrupt loss: read/write error or missed pong. */
44
44
  Unclean = 0,
45
- /** Graceful peer-initiated `disconnect` notification (RFC-450 §9.2). */
45
+ /** Graceful peer-initiated `disconnect` notification. */
46
46
  Clean = 1
47
47
  }
48
48
  /** Human-readable cause name for logging. */
@@ -155,22 +155,22 @@ declare const DEFAULT_DELIVERABLE_PHASES: ReadonlySet<string>;
155
155
 
156
156
  /**
157
157
  * Protocol-1 wire envelope: message types, encode/decode, NDJSON splitting,
158
- * and factory functions for the Soothe daemon (RFC-450).
158
+ * and factory functions for the Soothe daemon.
159
159
  *
160
160
  * The unified `{proto, type, method, params, id}` envelope combines
161
161
  * JSON-RPC 2.0's `method`/`params`/`id` structure with graphql-ws's `type`
162
162
  * semantics for message class distinction.
163
163
  */
164
164
 
165
- /** Protocol version string (RFC-450 §8.1). */
165
+ /** Protocol version string. */
166
166
  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.1";
171
171
  type MessageType = "connection_init" | "connection_ack" | "request" | "response" | "notification" | "subscribe" | "next" | "error" | "complete" | "unsubscribe" | "ping" | "pong" | "receipt_response" | "disconnect" | "status";
172
- /** Method names carried in the envelope `method` field (RFC-450 §9.2). */
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";
172
+ /** Method names carried in the envelope `method` field. */
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" | "autopilot_status" | "autopilot_submit" | "autopilot_list_goals" | "autopilot_get_goal" | "autopilot_cancel_goal" | "autopilot_cancel_all" | "autopilot_wake" | "autopilot_dream" | "autopilot_resume" | "autopilot_list_jobs" | "autopilot_get_job" | "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";
174
174
  /** Base fields shared by every protocol-1 message. */
175
175
  interface BaseEnvelope {
176
176
  proto: string;
@@ -194,7 +194,7 @@ interface NotificationEnvelope extends BaseEnvelope {
194
194
  type: "notification";
195
195
  method: MethodName;
196
196
  params?: Record<string, unknown>;
197
- /** Optional receipt id for delivery confirmation (RFC-450 §5.7). */
197
+ /** Optional receipt id for delivery confirmation. */
198
198
  receipt?: string;
199
199
  }
200
200
  /** Start a subscription stream (events arrive as `next`). */
@@ -276,9 +276,9 @@ interface DisconnectEnvelope extends BaseEnvelope {
276
276
  type: "disconnect";
277
277
  }
278
278
  /**
279
- * A daemon status frame. `status` is a defined protocol-1 top-level type
280
- * (RFC-450 §9.1): it passes through the daemon's legacy→`next` translator
281
- * unchanged, so it is NOT wrapped in a `next` envelope.
279
+ * A daemon status frame. `status` is a defined protocol-1 top-level type:
280
+ * it passes through the daemon's legacy→`next` translator unchanged, so it
281
+ * is NOT wrapped in a `next` envelope.
282
282
  */
283
283
  interface StatusFrame extends BaseEnvelope {
284
284
  type: "status";
@@ -370,7 +370,7 @@ declare function splitWirePayload(data: string): string[];
370
370
  * both shapes.
371
371
  */
372
372
  declare function extractSootheLoopID(msg: unknown): [string, boolean];
373
- /** Generates a new UUID correlation ID (RFC-450 §5.2 `id`). */
373
+ /** Generates a new UUID correlation ID. */
374
374
  declare function newRequestID(): string;
375
375
  /** Creates a `loop_input` notification envelope. */
376
376
  declare function newLoopInputMessage(loopID: string, content: string): NotificationEnvelope;
@@ -438,7 +438,7 @@ declare function isCompletionEvent(eventType: string): boolean;
438
438
  declare function isSubagentProgressEvent(eventType: string): boolean;
439
439
 
440
440
  /**
441
- * Client manages a WebSocket session with the Soothe daemon (RFC-450 protocol-1).
441
+ * Client manages a WebSocket session with the Soothe daemon.
442
442
  *
443
443
  * After close(), a new Client must be created to reconnect. The connection
444
444
  * begins with a bidirectional connection_init/connection_ack handshake; no
@@ -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
@@ -519,8 +524,8 @@ declare class Client extends EventEmitter {
519
524
  */
520
525
  private _signalDisconnect;
521
526
  /**
522
- * Re-dials the daemon and re-handshakes after a connection drop (RFC-450
523
- * §8.3). Does not re-establish loop subscriptions; follow with
527
+ * Re-dials the daemon and re-handshakes after a connection drop.
528
+ * Does not re-establish loop subscriptions; follow with
524
529
  * `reattachAndProbe()` to resume a loop session. The caller should invoke
525
530
  * this after the `'disconnected'` event fires. Reuses the same Client,
526
531
  * resetting the drop signal and multiplexer.
@@ -535,7 +540,7 @@ declare class Client extends EventEmitter {
535
540
  * Returns a `StaleLoopError` when the probe fails; callers should fall back
536
541
  * to a fresh `loop_new` bootstrap.
537
542
  *
538
- * Per RFC-629: connection-level readiness is the handshake's readiness_state
543
+ * Note: connection-level readiness is the handshake's readiness_state
539
544
  * (+ daemon_status); loop_get is a loop-scoped probe only, not a readiness
540
545
  * probe.
541
546
  */
@@ -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
@@ -567,9 +587,9 @@ declare class Client extends EventEmitter {
567
587
  private readLiveEventWithTimeout;
568
588
  /**
569
589
  * Sends a `request` envelope and waits for the matching `response` (or
570
- * `error`) correlated by `id` (RFC-450 §5/§9). Returns the `result` object.
590
+ * `error`) correlated by `id`. Returns the `result` object.
571
591
  *
572
- * Multiplexer-aware (RFC-629 constraint #1): registers a pending RPC wait
592
+ * Multiplexer-aware: registers a pending RPC wait
573
593
  * keyed by the request id so that, even when a `receiveMessages()` reader
574
594
  * is concurrently active, the matching `response`/`error` is routed to
575
595
  * this caller instead of being discarded or buffered behind a stream.
@@ -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
@@ -647,7 +669,7 @@ declare class Client extends EventEmitter {
647
669
  sendLoopStateUpdate(loopID: string, values: Record<string, unknown>, asNode?: string): Promise<void>;
648
670
  /** Requests display card ledger snapshot. */
649
671
  sendLoopCardsFetch(loopID: string): Promise<void>;
650
- /** Requests the full loop history (RFC-631). */
672
+ /** Requests the full loop history. */
651
673
  sendLoopHistoryFetch(loopID: string): Promise<void>;
652
674
  /** Requests MCP server status. */
653
675
  sendMCPStatus(): Promise<void>;
@@ -689,6 +711,32 @@ declare class Client extends EventEmitter {
689
711
  getJobDag(jobId: string, timeout?: number): Promise<Record<string, unknown>>;
690
712
  /** Sends guidance to a job or specific goal. */
691
713
  sendJobGuidance(jobId: string, text: string, goalId?: string, timeout?: number): Promise<Record<string, unknown>>;
714
+ /** Return autopilot scheduler status (running / dreaming / pool). */
715
+ autopilotStatus(timeout?: number): Promise<Record<string, unknown>>;
716
+ /** Submit a new autopilot goal (returns goal_id). */
717
+ autopilotSubmit(description: string, opts?: {
718
+ priority?: number;
719
+ workspace?: string;
720
+ timeout?: number;
721
+ }): Promise<Record<string, unknown>>;
722
+ /** List all goals (including non-root children). */
723
+ autopilotListGoals(timeout?: number): Promise<Record<string, unknown>>;
724
+ /** Fetch one goal by id. */
725
+ autopilotGetGoal(goalId: string, timeout?: number): Promise<Record<string, unknown>>;
726
+ /** Cancel a goal and its non-terminal descendants. */
727
+ autopilotCancelGoal(goalId: string, timeout?: number): Promise<Record<string, unknown>>;
728
+ /** Cancel every open (non-terminal) goal. */
729
+ autopilotCancelAll(timeout?: number): Promise<Record<string, unknown>>;
730
+ /** Exit dreaming mode and resume scheduling. */
731
+ autopilotWake(timeout?: number): Promise<Record<string, unknown>>;
732
+ /** Force dreaming mode. */
733
+ autopilotDream(timeout?: number): Promise<Record<string, unknown>>;
734
+ /** Resume a suspended or blocked goal. */
735
+ autopilotResume(goalId: string, timeout?: number): Promise<Record<string, unknown>>;
736
+ /** List root goals only (jobs). Prefer createJob / getJobStatus for job control. */
737
+ autopilotListJobs(timeout?: number): Promise<Record<string, unknown>>;
738
+ /** Get a root job with DAG snapshot. Prefer getJobStatus / getJobDag. */
739
+ autopilotGetJob(jobId: string, timeout?: number): Promise<Record<string, unknown>>;
692
740
  /** Subscribes to autopilot worker events. */
693
741
  autopilotSubscribe(timeout?: number): Promise<string>;
694
742
  /** Unsubscribes from autopilot worker events. */
@@ -710,86 +758,55 @@ declare class Client extends EventEmitter {
710
758
  }
711
759
 
712
760
  /**
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.
761
+ * Ephemeral one-shot RPC client for jobs / cron / autopilot.
762
+ * Mirrors Python AsyncCommandClient / CommandClient.
740
763
  */
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;
764
+
765
+ declare class CommandClient {
766
+ readonly url: string;
767
+ readonly timeoutMs: number;
768
+ private readonly config;
769
+ constructor(url: string, opts?: {
770
+ timeoutMs?: number;
771
+ config?: Config;
772
+ });
773
+ private withClient;
774
+ /** Generic one-shot RPC. */
775
+ request(method: MethodName, params?: Record<string, unknown>): Promise<Record<string, unknown>>;
776
+ jobCreate(goal: string, workspace?: string): Promise<Record<string, unknown>>;
777
+ jobStatus(jobId: string): Promise<Record<string, unknown>>;
778
+ jobCancel(jobId: string): Promise<Record<string, unknown>>;
779
+ /** Return autopilot scheduler status (running / dreaming / pool). */
780
+ autopilotStatus(): Promise<Record<string, unknown>>;
781
+ /** Submit a new autopilot goal (returns goal_id). */
782
+ autopilotSubmit(description: string, opts?: {
783
+ priority?: number;
784
+ workspace?: string;
785
+ }): Promise<Record<string, unknown>>;
786
+ /** List all goals (including non-root children). */
787
+ autopilotListGoals(): Promise<Record<string, unknown>>;
788
+ /** Fetch one goal by id. */
789
+ autopilotGetGoal(goalId: string): Promise<Record<string, unknown>>;
790
+ /** Cancel a goal and its non-terminal descendants. */
791
+ autopilotCancelGoal(goalId: string): Promise<Record<string, unknown>>;
792
+ /** Cancel every open (non-terminal) goal. */
793
+ autopilotCancelAll(): Promise<Record<string, unknown>>;
794
+ /** Exit dreaming mode and resume scheduling. */
795
+ autopilotWake(): Promise<Record<string, unknown>>;
796
+ /** Force dreaming mode. */
797
+ autopilotDream(): Promise<Record<string, unknown>>;
798
+ /** Resume a suspended or blocked goal. */
799
+ autopilotResume(goalId: string): Promise<Record<string, unknown>>;
800
+ /** List root goals only (jobs). Prefer job* for job control. */
801
+ autopilotListJobs(): Promise<Record<string, unknown>>;
802
+ /** Get a root job with DAG snapshot. Prefer jobStatus / getJobDag. */
803
+ autopilotGetJob(jobId: string): Promise<Record<string, unknown>>;
804
+ cronAdd(text: string, priority?: number): Promise<Record<string, unknown>>;
805
+ cronList(status?: string): Promise<Record<string, unknown>>;
789
806
  }
790
807
 
791
808
  /**
792
- * Convenience RPC helper functions for the Soothe client (RFC-450 protocol-1).
809
+ * Convenience RPC helper functions for the Soothe client.
793
810
  */
794
811
 
795
812
  /** Checks daemon status via RPC. */
@@ -804,12 +821,33 @@ declare function fetchSkillsCatalog(client: Client, timeout?: number): Promise<R
804
821
  declare function fetchConfigSection(client: Client, section: string, timeout?: number): Promise<Record<string, unknown>>;
805
822
  /** Requests daemon config reload via RPC. */
806
823
  declare function requestDaemonConfigReload(client: Client, timeout?: number): Promise<Record<string, unknown>>;
807
- /** Requests loop history (RFC-631) and waits for the response. */
824
+ /** Requests loop history and waits for the response. */
808
825
  declare function fetchLoopHistory(client: Client, loopID: string, timeout?: number): Promise<Record<string, unknown>>;
809
826
  /** Submits credentials for daemon-side authentication and waits for the response. */
810
827
  declare function authenticate(client: Client, accessKey: string, secretKey: string, timeout?: number): Promise<Record<string, unknown>>;
811
828
  /** Refreshes the daemon-side auth token and waits for the response. */
812
829
  declare function refreshAuthToken(client: Client, refreshToken: string, timeout?: number): Promise<Record<string, unknown>>;
830
+ /** Fetch bound display-card snapshot for a loop. */
831
+ declare function fetchLoopCards(client: Client, loopID: string, timeout?: number): Promise<Record<string, unknown>>;
832
+ /** Fetch persisted conversation/activity rows for a loop. */
833
+ declare function fetchLoopMessages(client: Client, loopID: string, opts?: {
834
+ limit?: number;
835
+ offset?: number;
836
+ includeEvents?: boolean;
837
+ timeout?: number;
838
+ }): Promise<Record<string, unknown>>;
839
+ /**
840
+ * Connect, handshake, and yield a ready Client. Always closes in finally.
841
+ */
842
+ declare function connectedWebsocket<T>(wsUrl: string, fn: (client: Client) => Promise<T>, timeoutMs?: number): Promise<T>;
843
+ /**
844
+ * One-shot protocol-1 RPC / notify / subscribe with dict-style error contract.
845
+ * Callers check `if ("error" in response)`.
846
+ */
847
+ declare function protocol1Rpc(wsUrl: string, method: string, params?: Record<string, unknown> | null, opts?: {
848
+ mode?: "request" | "notify" | "subscribe";
849
+ timeoutMs?: number;
850
+ }): Promise<Record<string, unknown>>;
813
851
 
814
852
  /**
815
853
  * loop_new (or reuse id) → subscribe(loop_events); returns the loop id.
@@ -829,7 +867,26 @@ declare function waitSubscriptionConfirmed(client: Client, wantLoopID: string, _
829
867
  declare function connectWithRetries(client: Client, maxRetries?: number, retryDelay?: number): Promise<void>;
830
868
 
831
869
  /**
832
- * Persistence seam for appkit (RFC-629 Layer 1).
870
+ * Shared stream/turn terminal frame helpers for Client and DaemonSession.
871
+ *
872
+ * Keeps peel-at-turn-start and turn-end detection on one vocabulary so leftover
873
+ * prior-goal terminals cannot blank the next query.
874
+ */
875
+ /** Daemon turn-scoped stream end custom type. */
876
+ declare const STREAM_END = "soothe.stream.end";
877
+ /** True when `data` is a turn-scoped terminal custom payload. */
878
+ declare function isTurnEndCustomData(data: unknown): data is Record<string, unknown>;
879
+ /**
880
+ * True when a chunk proves the active turn has non-intake progress.
881
+ * Used so late prior-goal stream.end cannot close a turn that has only seen
882
+ * intake lifecycle (e.g. plan.phase).
883
+ */
884
+ declare function isTurnProgressChunk(mode: string, data: unknown): boolean;
885
+ /** True when the client should bump delivery_ack sequence for this frame. */
886
+ declare function inboundNeedsDeliveryAck(event: Record<string, unknown>): boolean;
887
+
888
+ /**
889
+ * Persistence seam for appkit.
833
890
  *
834
891
  * SessionStore abstracts per-application storage: the session↔loop-id mapping
835
892
  * that ConnectionPool consults to decide bootstrap vs reattach, and the
@@ -890,7 +947,7 @@ interface SessionStore {
890
947
  }
891
948
 
892
949
  /**
893
- * SSE-style pub/sub fan-out for appkit (RFC-629 Layer 1).
950
+ * SSE-style pub/sub fan-out for appkit.
894
951
  *
895
952
  * Generic, string-keyed pub/sub for SSE-style event delivery. The
896
953
  * application-agnostic successor to a domain-keyed broadcaster: applications
@@ -938,7 +995,7 @@ declare class SSEBroadcaster {
938
995
  }
939
996
 
940
997
  /**
941
- * Thinking-step extraction for appkit (RFC-629 Layer 1).
998
+ * Thinking-step extraction for appkit.
942
999
  *
943
1000
  * Maps an allowlisted progress event to one structured UI line. Free-form
944
1001
  * streams (tokens, reports, reasoning) are excluded. Ported from the Go
@@ -954,18 +1011,17 @@ declare const DEFAULT_THINKING_STEP_EVENTS: ReadonlySet<string>;
954
1011
  declare function extractThinkingStep(eventType: string, data: Record<string, unknown> | null, allow?: ReadonlySet<string>): [string, boolean];
955
1012
 
956
1013
  /**
957
- * Event classifier for appkit (RFC-629 Layer 1).
1014
+ * Event classifier for appkit.
958
1015
  *
959
1016
  * Maps a stream of decoded daemon events into deliverable/streaming/terminal
960
- * outcomes, keyed on (namespace, mode, phase) per RFC-614/RFC-403
961
- * (RFC-629 constraint #4). The app-agnostic successor to triarch's
962
- * ProcessChatEvent, with the deliverable phase set promoted from hardcoded
963
- * constants to configuration.
1017
+ * outcomes, keyed on (namespace, mode, phase). The app-agnostic successor to
1018
+ * product-specific ProcessChatEvent helpers, with the deliverable phase set
1019
+ * promoted from hardcoded constants to configuration.
964
1020
  *
965
1021
  * Event shape: a protocol-1 `next` envelope carries
966
1022
  * `{type:"next", payload:{namespace, mode, data, loop_id}}`. The daemon
967
1023
  * wraps legacy free-form frames as `{payload:{namespace, mode:<orig type>,
968
- * data:<orig frame>}}` (RFC-450 §9.3). The classifier inspects the payload's
1024
+ * data:<orig frame>}}`. The classifier inspects the payload's
969
1025
  * `mode`/`data`/`namespace` and the inner message's `phase`/`type`/`content`.
970
1026
  */
971
1027
 
@@ -1004,12 +1060,19 @@ interface ClassifierConfig {
1004
1060
  minDeliverableRunes?: number;
1005
1061
  /** Optional app override of the default thinking-step event allowlist. */
1006
1062
  thinkingStepEvents?: ReadonlySet<string>;
1063
+ /**
1064
+ * When true, a status frame with state=idle and non-empty accumulated
1065
+ * assistant text is DeliverableComplete (typical for direct-model turns).
1066
+ * Default false keeps Continue-on-status behaviour.
1067
+ */
1068
+ treatStatusIdleAsComplete?: boolean;
1007
1069
  }
1008
1070
  /** Maps a stream of decoded daemon events into deliverable/streaming/terminal outcomes. */
1009
1071
  declare class EventClassifier {
1010
1072
  private deliverablePhases;
1011
1073
  private minDeliverableRunes;
1012
1074
  private thinkingStepEvents?;
1075
+ private treatStatusIdleAsComplete;
1013
1076
  constructor(cfg: ClassifierConfig);
1014
1077
  /**
1015
1078
  * Inspects one decoded event and returns its outcome. `accumulated` is the
@@ -1056,7 +1119,7 @@ declare class EventClassifier {
1056
1119
  }
1057
1120
 
1058
1121
  /**
1059
- * Single-flight query gate for appkit (RFC-629 Layer 1).
1122
+ * Single-flight query gate for appkit.
1060
1123
  *
1061
1124
  * Enforces single-flight query execution per session id and the
1062
1125
  * cancel-before-context ordering: when a query is cancelled, the daemon is
@@ -1104,7 +1167,7 @@ declare class QueryGate {
1104
1167
 
1105
1168
  /**
1106
1169
  * ManagedClient — the subset of the core Client that appkit's ConnectionPool
1107
- * and TurnRunner depend on (RFC-629 Layer 1).
1170
+ * and TurnRunner depend on.
1108
1171
  *
1109
1172
  * The concrete `Client` satisfies it; tests supply a fake. Defining it as an
1110
1173
  * interface lets appkit be unit-tested without a live WebSocket daemon.
@@ -1142,19 +1205,15 @@ interface ManagedClient {
1142
1205
  * (e.g. wrapping Client with logging/metrics).
1143
1206
  */
1144
1207
  type ClientFactory = (url: string, config?: Config) => ManagedClient;
1145
- /** Returns a ClientFactory that builds a core Client. */
1146
- declare function defaultClientFactory(): ClientFactory;
1147
1208
  /**
1148
1209
  * Creates a new loop (loop_new + subscribe) on a connected client and returns
1149
1210
  * the new loop id. The default implementation calls bootstrapLoopSession;
1150
1211
  * apps may override it.
1151
1212
  */
1152
1213
  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
1214
 
1156
1215
  /**
1157
- * Per-session connection pool for appkit (RFC-629 Layer 1).
1216
+ * Per-session connection pool for appkit.
1158
1217
  *
1159
1218
  * Manages a pool of daemon connections, one active per session. Reuses an
1160
1219
  * active connection when still live, otherwise bootstraps a fresh loop
@@ -1178,7 +1237,8 @@ interface PoolConfig {
1178
1237
  maxIdleTime: number;
1179
1238
  healthCheckInterval: number;
1180
1239
  }
1181
- /** Returns env-overridable defaults (mirrors triarch). */
1240
+ /** Returns env-overridable defaults (mirrors triarch).
1241
+ * `maxIdleTime` is enforced on acquire; `healthCheckInterval` is reserved. */
1182
1242
  declare function defaultPoolConfig(): PoolConfig;
1183
1243
  /** One connection slot in the pool. */
1184
1244
  declare class PooledConn {
@@ -1247,23 +1307,76 @@ declare class ConnectionPool {
1247
1307
  }
1248
1308
 
1249
1309
  /**
1250
- * Turn runner for appkit (RFC-629 Layer 1).
1310
+ * Attachment image compaction for appkit.
1311
+ *
1312
+ * When `sharp` is installed (optionalDependency), oversized image/* payloads
1313
+ * are downscaled. Without sharp, attachments pass through unchanged.
1314
+ */
1315
+ interface CompactImageOptions {
1316
+ /** Max width or height in pixels. Default 768. */
1317
+ maxDim?: number;
1318
+ /** JPEG encode quality 1–100. Default 85. */
1319
+ jpegQuality?: number;
1320
+ }
1321
+ /**
1322
+ * Downscales image/* payloads when either dimension exceeds MaxDim.
1323
+ * Non-images and decode failures pass through unchanged.
1324
+ * PNG stays PNG; other image types re-encode as JPEG when sharp is available.
1325
+ */
1326
+ declare function compactImageAttachment(mimeType: string, dataB64: string, opts?: CompactImageOptions | null): Promise<[string, string]>;
1327
+ /**
1328
+ * Applies compactImageAttachment to each attachment map with mime_type + data.
1329
+ */
1330
+ declare function compactAttachments(atts: Record<string, unknown>[], opts?: CompactImageOptions | null): Promise<Record<string, unknown>[]>;
1331
+
1332
+ /**
1333
+ * Turn runner for appkit.
1251
1334
  *
1252
1335
  * Executes one query turn end-to-end: acquire a pooled connection, enforce
1253
1336
  * single-flight, send loop_input, consume the event stream, classify events,
1254
1337
  * resolve the deliverable, persist the reply, and broadcast completion.
1255
1338
  *
1256
- * The app-agnostic successor to triarch's ExecuteQuery.
1339
+ * Supports lifecycle knobs: idle timeout, soft-complete
1340
+ * policies, attachment compaction, and stream-close soft-complete.
1257
1341
  */
1258
1342
 
1259
- /** Returned when a turn exceeds the configured timeout. */
1343
+ /** Returned when a turn exceeds the configured timeout and policy is Fail. */
1260
1344
  declare class ErrQueryTimeout extends Error {
1261
1345
  constructor();
1262
1346
  }
1347
+ /** Returned when no events arrive within IdleTimeout and policy is Fail. */
1348
+ declare class ErrIdleTimeout extends Error {
1349
+ constructor();
1350
+ }
1351
+ /** Selects fail vs soft-complete behaviour for idle, query, and stream-close. */
1352
+ declare enum TimeoutPolicy {
1353
+ Fail = 0,
1354
+ SoftComplete = 1
1355
+ }
1356
+ type StreamClosePolicy = TimeoutPolicy;
1357
+ declare const StreamCloseFail = TimeoutPolicy.Fail;
1358
+ declare const StreamCloseSoftComplete = TimeoutPolicy.SoftComplete;
1263
1359
  /** Configures a TurnRunner. */
1264
1360
  interface TurnConfig {
1265
1361
  /** Per-turn deadline in ms. Defaults to 30m. */
1266
1362
  queryTimeout: number;
1363
+ /** Max silence between classified events in ms. Zero disables (default). */
1364
+ idleTimeout?: number;
1365
+ /**
1366
+ * When > 0, raises idleTimeout for turns with attachments if idleTimeout
1367
+ * is positive but below this floor.
1368
+ */
1369
+ minIdleTimeoutWithAttachments?: number;
1370
+ /** Fail vs soft-complete when the idle watchdog fires. Default Fail. */
1371
+ onIdleTimeout?: TimeoutPolicy;
1372
+ /** Fail vs soft-complete when queryTimeout fires. Default Fail. */
1373
+ onQueryTimeout?: TimeoutPolicy;
1374
+ /** Fail vs soft-complete when the event stream closes. Default Fail. */
1375
+ onStreamClose?: StreamClosePolicy;
1376
+ /** Run compactAttachments before buildInput. Default false. */
1377
+ compactAttachmentsBeforeSend?: boolean;
1378
+ /** Overrides for compactAttachmentsBeforeSend. */
1379
+ compactImageOpts?: CompactImageOptions | null;
1267
1380
  }
1268
1381
  /** Carries optional daemon hints on a loop_input payload. */
1269
1382
  interface InputOpts {
@@ -1273,13 +1386,15 @@ interface InputOpts {
1273
1386
  responseSchemaName?: string;
1274
1387
  responseSchemaStrict?: boolean;
1275
1388
  }
1276
- /** Optional attachment shape (IG-327: {mime_type, data(base64)}). */
1389
+ /** Optional attachment shape ({mime_type, data(base64)}). */
1277
1390
  type Attachment = Record<string, unknown>;
1278
1391
  /**
1279
1392
  * Builds a loop_input payload with optional attachments. Apps build this from
1280
1393
  * their product modes (e.g. triarch's ask/agent/deep-research).
1281
1394
  */
1282
1395
  declare function inputMessageForLoop(text: string, loopID: string, attachments?: Attachment[], opts?: InputOpts): Record<string, unknown>;
1396
+ /** Effective idle timeout for a turn (attachment floor applied). */
1397
+ declare function idleTimeoutForTurn(cfg: TurnConfig, hasAttachments: boolean): number;
1283
1398
  /** Completion hook signature. */
1284
1399
  type OnComplete = (sessionID: string, loopID: string, content: string, completionEvent: string, elapsedMs: number) => void;
1285
1400
  /** Error hook signature. */
@@ -1297,25 +1412,13 @@ declare class TurnRunner {
1297
1412
  private buildInput;
1298
1413
  private onComplete;
1299
1414
  private onError;
1300
- /**
1301
- * Constructs a TurnRunner. pool, gate, classifier, and store are required;
1302
- * broadcaster may be null.
1303
- */
1304
1415
  constructor(pool: ConnectionPool, gate: QueryGate, classifier: EventClassifier, store: SessionStore, broadcaster: SSEBroadcaster | null, cfg: TurnConfig);
1305
- /** Overrides the loop_input payload builder. */
1306
1416
  withInputBuilder(f: typeof inputMessageForLoop): TurnRunner;
1307
- /** Sets a completion hook (runs inline on success). */
1308
1417
  withOnComplete(f: OnComplete): TurnRunner;
1309
- /** Sets an error hook (runs inline on failure). */
1310
1418
  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
1419
  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. */
1420
+ private finishTimeout;
1421
+ private completeTurn;
1319
1422
  private sendLoopCancel;
1320
1423
  private persistResponse;
1321
1424
  private persistFailed;
@@ -1324,4 +1427,120 @@ declare class TurnRunner {
1324
1427
  private broadcastError;
1325
1428
  }
1326
1429
 
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 };
1430
+ /**
1431
+ * Per-turn observability counters for daemon stream consumption.
1432
+ */
1433
+ declare class TurnEventStats {
1434
+ total: number;
1435
+ messages: number;
1436
+ updates: number;
1437
+ custom: number;
1438
+ skipped: number;
1439
+ filteredEarly: number;
1440
+ toolCalls: number;
1441
+ toolResults: number;
1442
+ textChunks: number;
1443
+ heartbeatsDropped: number;
1444
+ postIdleDrained: number;
1445
+ inboundDropped: number;
1446
+ }
1447
+
1448
+ /**
1449
+ * Dual-socket daemon loop session with turn streaming (Python DaemonSession parity).
1450
+ *
1451
+ * Owns a subscribed stream WebSocket plus an RPC sidecar so metadata calls do not
1452
+ * starve loop events. `iterTurnChunks` handles idle timeout, post-idle drain,
1453
+ * loop scoping, and connection-loss detection.
1454
+ */
1455
+
1456
+ declare const DEFAULT_POST_IDLE_DRAIN_MS = 500;
1457
+ type EarlyDropFn = (namespace: unknown[], mode: string, data: unknown) => boolean;
1458
+ type StatsFactory = () => TurnEventStats;
1459
+ type StreamDeliveryResolver = () => string;
1460
+ interface DaemonSessionOptions {
1461
+ workspace?: string | null;
1462
+ streamDelivery?: string | StreamDeliveryResolver;
1463
+ postIdleDrainDeadlineMs?: number;
1464
+ earlyDropFn?: EarlyDropFn | null;
1465
+ statsFactory?: StatsFactory | null;
1466
+ config?: Config;
1467
+ }
1468
+ type TurnChunk = [namespace: unknown[], mode: string, data: unknown];
1469
+ /** Daemon-backed loop session with stream + RPC sockets. */
1470
+ declare class DaemonSession {
1471
+ private wsUrl;
1472
+ private workspace;
1473
+ private streamDelivery;
1474
+ private client;
1475
+ private rpcClient;
1476
+ private loopId;
1477
+ private readBusy;
1478
+ private rpcBusy;
1479
+ private rpcConnected;
1480
+ private streaming;
1481
+ private postIdleDrainDeadlineMs;
1482
+ private closed;
1483
+ private earlyDropFn;
1484
+ private statsFactory;
1485
+ private config;
1486
+ turnEventStats: TurnEventStats;
1487
+ lastTurnEndState: string | null;
1488
+ lastTurnCancellationSeen: boolean;
1489
+ lastTurnErrorMessage: string | null;
1490
+ constructor(wsUrl: string, opts?: DaemonSessionOptions);
1491
+ get streamClient(): Client;
1492
+ get rpcSideClient(): Client;
1493
+ get activeLoopId(): string | null;
1494
+ private resolveStreamDeliveryMode;
1495
+ get streamDeliveryMode(): string;
1496
+ private shouldDrop;
1497
+ connect(resumeLoopId?: string | null): Promise<Record<string, unknown>>;
1498
+ private bootstrapLoop;
1499
+ newLoop(): Promise<Record<string, unknown>>;
1500
+ switchLoop(loopId: string): Promise<Record<string, unknown>>;
1501
+ ensureConnected(): Promise<void>;
1502
+ close(): Promise<void>;
1503
+ detach(): Promise<void>;
1504
+ sendTurn(text: string, options?: {
1505
+ autonomous?: boolean;
1506
+ maxIterations?: number;
1507
+ preferredSubagent?: string;
1508
+ model?: string;
1509
+ modelParams?: Record<string, unknown>;
1510
+ attachments?: Array<{
1511
+ mime_type: string;
1512
+ data: string;
1513
+ }>;
1514
+ clarificationMode?: string;
1515
+ clarificationAnswer?: boolean;
1516
+ intentHint?: string;
1517
+ }): Promise<void>;
1518
+ cancelActiveTurn(): Promise<void>;
1519
+ private drainStreamEventsAfterIdle;
1520
+ private withRpcLock;
1521
+ private ensureRpcConnected;
1522
+ listLoops(_limit?: number): Promise<Record<string, unknown>>;
1523
+ fetchLoopCards(loopId: string): Promise<{
1524
+ cards: unknown[];
1525
+ seq: number;
1526
+ contextTokens: number;
1527
+ success: boolean;
1528
+ }>;
1529
+ fetchLoopHistory(loopId: string): Promise<{
1530
+ goals: unknown[];
1531
+ liveCards: unknown[];
1532
+ liveGoalIndex: number | null;
1533
+ contextTokens: number;
1534
+ success: boolean;
1535
+ }>;
1536
+ fetchConversationLog(loopId: string, opts?: {
1537
+ limit?: number;
1538
+ offset?: number;
1539
+ includeEvents?: boolean;
1540
+ }): Promise<Record<string, unknown>[]>;
1541
+ iterTurnChunks(opts?: {
1542
+ maxWaitMs?: number;
1543
+ }): AsyncGenerator<TurnChunk>;
1544
+ }
1545
+
1546
+ 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 };