@parall/sdk 1.30.0 → 1.32.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/src/types.ts CHANGED
@@ -104,15 +104,22 @@ export interface TransferChatOwnershipRequest {
104
104
  export interface UnreadEntry {
105
105
  count: number;
106
106
  mentions: number;
107
+ since?: string;
108
+ }
109
+
110
+ export interface ThreadUnreadEntry {
111
+ unread: number;
112
+ total: number;
113
+ since: string | null;
107
114
  }
108
115
 
109
116
  export type MessageType =
110
117
  | 'text'
111
- | 'file' // deprecated: attachments are now schema-level on Message
112
- | 'tool_call' // deprecated: use AgentStep
113
- | 'tool_result' // deprecated: use AgentStep
114
- | 'approval_card' // deprecated: use 'card' with card_type='approval'
115
- | 'state_delta' // deprecated: use AgentStep
118
+ | 'file' // deprecated: attachments are now schema-level on Message
119
+ | 'tool_call' // deprecated: use AgentStep
120
+ | 'tool_result' // deprecated: use AgentStep
121
+ | 'approval_card' // deprecated: use 'card' with card_type='approval'
122
+ | 'state_delta' // deprecated: use AgentStep
116
123
  | 'card'
117
124
  | 'system';
118
125
 
@@ -197,7 +204,13 @@ export type CardContent =
197
204
  | ApprovalCardContent
198
205
  | { card_type: string; entity_id?: string; data?: Record<string, unknown> };
199
206
 
200
- export type AgentState = 'thinking' | 'tool_calling' | 'streaming' | 'waiting_approval' | 'completed' | 'error';
207
+ export type AgentState =
208
+ | 'thinking'
209
+ | 'tool_calling'
210
+ | 'streaming'
211
+ | 'waiting_approval'
212
+ | 'completed'
213
+ | 'error';
201
214
 
202
215
  export interface StateDeltaContent {
203
216
  state: AgentState;
@@ -317,6 +330,9 @@ export interface Organization {
317
330
  created_at: string;
318
331
  /** Per-member flag: true when the user has dismissed the onboarding popup for this org. */
319
332
  onboarding_dismissed: boolean;
333
+ /** Caller's membership role in this org (owner/admin/member). Present on the
334
+ * GET /orgs list response; omitted on single-org fetches that don't join membership. */
335
+ role?: OrgMemberRole;
320
336
  }
321
337
 
322
338
  export interface OrgInviteCode {
@@ -367,6 +383,52 @@ export interface InvitationPublicInfo {
367
383
  expires_at: string;
368
384
  }
369
385
 
386
+ // ---- Org-level shareable invite link ----
387
+
388
+ /** Single regenerable token per org. Sits alongside (not replacing) the
389
+ * per-email OrgInvitation flow. */
390
+ export interface OrgInviteLink {
391
+ org_id: string;
392
+ token: string;
393
+ require_approval: boolean;
394
+ expires_at: string;
395
+ created_at: string;
396
+ regenerated_at: string;
397
+ }
398
+
399
+ export interface JoinByLinkRequest {
400
+ token: string;
401
+ }
402
+
403
+ export interface JoinByLinkResponse {
404
+ org_id: string;
405
+ joined: boolean;
406
+ status: 'active' | 'pending_approval' | 'already_member';
407
+ join_request_id?: string;
408
+ /** Minimal org summary so the join page can render the real org name
409
+ * in success / pending-approval copy without a second round-trip. */
410
+ org?: JoinByLinkOrgInfo;
411
+ }
412
+
413
+ export interface JoinByLinkOrgInfo {
414
+ id: string;
415
+ name: string;
416
+ avatar_url?: string | null;
417
+ }
418
+
419
+ export type OrgJoinRequestStatus = 'pending' | 'approved' | 'rejected';
420
+
421
+ export interface OrgJoinRequest {
422
+ id: string;
423
+ org_id: string;
424
+ user_id: string;
425
+ status: OrgJoinRequestStatus;
426
+ decided_by?: string;
427
+ decided_at?: string;
428
+ created_at: string;
429
+ user?: User;
430
+ }
431
+
370
432
  export interface CreateInvitationRequest {
371
433
  email: string;
372
434
  role?: OrgMemberRole;
@@ -571,11 +633,10 @@ export type AgentLLMSource = 'parall' | 'custom' | 'runtime_auth';
571
633
  * `llm_source` makes that source explicit. Missing values are backward-
572
634
  * compatible: empty config means Parall provided, while legacy rows with
573
635
  * credential fields but no source are inferred as custom. Custom provider
574
- * fields let admins bring their own ChatGPT / Anthropic subscription, point
575
- * at Azure OpenAI, or use an OpenAI / Anthropic-compatible proxy.
576
- * `runtime_auth` is the runtime-local sign-in path (Claude.ai OAuth today);
577
- * OAuth is the helper that writes credentials for that source, not model /
578
- * effort control.
636
+ * fields let admins bring their own OpenAI / Anthropic subscription, point
637
+ * at Azure OpenAI, or use an OpenAI / Anthropic-compatible proxy. Hosted
638
+ * runtime OAuth is no longer accepted; self-hosted daemon runtimes manage
639
+ * local CLI OAuth outside provider_config.
579
640
  *
580
641
  * Each runtime consumes exactly one credential family:
581
642
  * - codex → openai_*
@@ -631,7 +692,14 @@ export interface UpdateAgentRequest {
631
692
 
632
693
  // ---- Machine types ----
633
694
 
634
- export type MachineStatus = 'provisioning' | 'starting' | 'restarting' | 'running' | 'stopped' | 'error' | 'terminated';
695
+ export type MachineStatus =
696
+ | 'provisioning'
697
+ | 'starting'
698
+ | 'restarting'
699
+ | 'running'
700
+ | 'stopped'
701
+ | 'error'
702
+ | 'terminated';
635
703
 
636
704
  export interface Machine {
637
705
  id: string;
@@ -650,6 +718,7 @@ export interface Machine {
650
718
  daemon_mode: boolean;
651
719
  llm_source?: string;
652
720
  compute_mode: 'hosted' | 'local';
721
+ daemon_version?: string | null;
653
722
  region: string | null;
654
723
  created_by: string;
655
724
  created_at: string;
@@ -811,6 +880,20 @@ export interface MachineFilesystemBrowseData {
811
880
  path: string;
812
881
  }
813
882
 
883
+ export interface MachineUpdateData {
884
+ machine_id: string;
885
+ new_version: string;
886
+ mandatory: boolean;
887
+ reason?: string;
888
+ }
889
+
890
+ export interface MachineClipInstallData {
891
+ clip_id: string;
892
+ alias: string;
893
+ source_ref: string;
894
+ version?: string;
895
+ }
896
+
814
897
  export interface AgentNewSessionData {
815
898
  previous_session_id?: string;
816
899
  }
@@ -876,8 +959,20 @@ export interface AvatarUploadResponse {
876
959
 
877
960
  export type TaskStatus = 'todo' | 'in_progress' | 'in_review' | 'done' | 'canceled';
878
961
  export type TaskPriority = 'high' | 'normal' | 'low';
879
- export type TaskRelationTargetType = 'task' | 'message' | 'chat' | 'agent_session' | 'wiki_changeset';
880
- export type TaskRelationType = 'blocks' | 'related' | 'duplicate' | 'source' | 'reference' | 'discussion' | 'execution';
962
+ export type TaskRelationTargetType =
963
+ | 'task'
964
+ | 'message'
965
+ | 'chat'
966
+ | 'agent_session'
967
+ | 'wiki_changeset';
968
+ export type TaskRelationType =
969
+ | 'blocks'
970
+ | 'related'
971
+ | 'duplicate'
972
+ | 'source'
973
+ | 'reference'
974
+ | 'discussion'
975
+ | 'execution';
881
976
 
882
977
  export interface Task {
883
978
  id: string;
@@ -943,6 +1038,24 @@ export interface TaskRelation {
943
1038
  created_at: string;
944
1039
  }
945
1040
 
1041
+ export type RefSearchKind = 'user' | 'task' | 'channel';
1042
+
1043
+ export interface RefSearchItem {
1044
+ kind: RefSearchKind;
1045
+ id: string;
1046
+ uri: string;
1047
+ display: string;
1048
+ label: string;
1049
+ title: string;
1050
+ subtitle?: string;
1051
+ subtitle_key?: string;
1052
+ status?: string;
1053
+ }
1054
+
1055
+ export interface RefSearchResponse {
1056
+ data: RefSearchItem[];
1057
+ }
1058
+
946
1059
  export interface CreateTaskRequest {
947
1060
  title: string;
948
1061
  description?: string;
@@ -1026,6 +1139,8 @@ export interface Schedule {
1026
1139
  attached_to_uri: string | null;
1027
1140
  name: string;
1028
1141
  description: string;
1142
+ attachment_ids: string[];
1143
+ attachments?: Attachment[];
1029
1144
  spec_type: ScheduleSpecType;
1030
1145
  cron_expr: string | null;
1031
1146
  interval_seconds: number | null;
@@ -1054,6 +1169,8 @@ export interface ScheduleRun {
1054
1169
  status: ScheduleRunStatus;
1055
1170
  fired_description: string | null;
1056
1171
  fired_attached_uri: string | null;
1172
+ fired_attachment_ids: string[];
1173
+ fired_attachments?: Attachment[];
1057
1174
  error: string | null;
1058
1175
  created_at: string;
1059
1176
  }
@@ -1063,6 +1180,7 @@ export interface CreateScheduleInput {
1063
1180
  description: string;
1064
1181
  target_ids: string[];
1065
1182
  attached_to_uri?: string;
1183
+ attachment_ids?: string[];
1066
1184
  spec_type: ScheduleSpecType;
1067
1185
  cron_expr?: string;
1068
1186
  interval_seconds?: number;
@@ -1082,6 +1200,9 @@ export interface UpdateScheduleInput {
1082
1200
  attached_to_uri?: string;
1083
1201
  /** Explicitly clear attached_to_uri. Server honors this over `attached_to_uri`. */
1084
1202
  attached_to_uri_clear?: boolean;
1203
+ attachment_ids?: string[];
1204
+ /** Explicitly clear attachment_ids. Server honors this over `attachment_ids`. */
1205
+ attachment_ids_clear?: boolean;
1085
1206
  cron_expr?: string;
1086
1207
  interval_seconds?: number;
1087
1208
  run_at?: string;
@@ -1561,7 +1682,23 @@ export interface ChatCreatedData extends Chat {}
1561
1682
 
1562
1683
  export interface ChatUpdateData {
1563
1684
  chat_id: string;
1564
- changes: Partial<Pick<Chat, 'name' | 'avatar_url' | 'description' | 'visibility' | 'agent_routing_mode' | 'smart_routing_strategy' | 'smart_routing_agent_id' | 'last_message_at' | 'last_message_preview' | 'last_message_sender' | 'archived_at' | 'deleted_at'>>;
1685
+ changes: Partial<
1686
+ Pick<
1687
+ Chat,
1688
+ | 'name'
1689
+ | 'avatar_url'
1690
+ | 'description'
1691
+ | 'visibility'
1692
+ | 'agent_routing_mode'
1693
+ | 'smart_routing_strategy'
1694
+ | 'smart_routing_agent_id'
1695
+ | 'last_message_at'
1696
+ | 'last_message_preview'
1697
+ | 'last_message_sender'
1698
+ | 'archived_at'
1699
+ | 'deleted_at'
1700
+ >
1701
+ >;
1565
1702
  }
1566
1703
 
1567
1704
  export interface ChatDeletedData {
@@ -1666,7 +1803,7 @@ export interface AgentSessionDB {
1666
1803
  id: string;
1667
1804
  agent_id: string;
1668
1805
  org_id: string;
1669
- status: string; // open | closed | failed | cancelled | superseded
1806
+ status: string; // open | closed | failed | cancelled | superseded
1670
1807
  runtime_type: string;
1671
1808
  runtime_key: string | null;
1672
1809
  runtime_lane_key: string;
@@ -1677,6 +1814,13 @@ export interface AgentSessionDB {
1677
1814
  started_at: string;
1678
1815
  finished_at: string | null;
1679
1816
  created_at: string;
1817
+
1818
+ // Computed fields populated by ListSessions enrichment.
1819
+ trigger_chat_id?: string | null;
1820
+ trigger_chat_name?: string | null;
1821
+ trigger_chat_type?: string | null;
1822
+ trigger_sender_name?: string | null;
1823
+ step_count?: number | null;
1680
1824
  }
1681
1825
 
1682
1826
  export interface AgentStep {
@@ -1755,6 +1899,7 @@ export interface Comment {
1755
1899
  export interface CreateCommentRequest {
1756
1900
  target_uri: string;
1757
1901
  body: string;
1902
+ parent_id?: string;
1758
1903
  }
1759
1904
 
1760
1905
  export interface UpdateCommentRequest {
@@ -1774,9 +1919,14 @@ export interface CommentDeletedData {
1774
1919
  // ============================================================
1775
1920
 
1776
1921
  export type InboxItemType =
1777
- | 'mention' | 'task_assign' | 'task_update'
1778
- | 'task_comment' | 'approval_request'
1779
- | 'agent_alert' | 'invitation' | 'schedule_fire'
1922
+ | 'mention'
1923
+ | 'task_assign'
1924
+ | 'task_update'
1925
+ | 'task_comment'
1926
+ | 'approval_request'
1927
+ | 'agent_alert'
1928
+ | 'invitation'
1929
+ | 'schedule_fire'
1780
1930
  | 'thread_reply';
1781
1931
 
1782
1932
  export interface InboxItem {
@@ -1808,8 +1958,15 @@ export interface InboxItem {
1808
1958
  // Dispatch Types (agent event delivery)
1809
1959
  // ============================================================
1810
1960
 
1811
- export type DispatchEventType = 'message' | 'task_assign' | 'task_update' | 'task_comment' | 'schedule.fire' | 'approval_decided';
1812
- export type DispatchStatus = 'pending' | 'acked';
1961
+ export type DispatchEventType =
1962
+ | 'message'
1963
+ | 'task_assign'
1964
+ | 'task_update'
1965
+ | 'task_comment'
1966
+ | 'wiki_comment'
1967
+ | 'schedule.fire'
1968
+ | 'approval_decided';
1969
+ export type DispatchStatus = 'pending' | 'received' | 'acked';
1813
1970
  export type DispatchDeliveryReason = 'mention' | 'watcher' | 'assignee' | 'creator';
1814
1971
 
1815
1972
  export interface DispatchEvent {
@@ -1842,6 +1999,16 @@ export interface DispatchEvent {
1842
1999
 
1843
2000
  export type DispatchNewData = DispatchEvent;
1844
2001
 
2002
+ export interface DispatchReceivedData {
2003
+ agent_id: string;
2004
+ event_type: string;
2005
+ source_type: string;
2006
+ source_id: string;
2007
+ chat_id?: string | null;
2008
+ task_id?: string | null;
2009
+ org_id: string;
2010
+ }
2011
+
1845
2012
  export type InboxNewData = InboxItem;
1846
2013
 
1847
2014
  export interface InboxUpdateData {
@@ -1873,7 +2040,7 @@ export interface NotificationAlertData {
1873
2040
  }
1874
2041
 
1875
2042
  export type WsEventMap = {
1876
- 'hello': HelloData;
2043
+ hello: HelloData;
1877
2044
  'message.new': MessageNewData;
1878
2045
  'message.patch': MessagePatchData;
1879
2046
  'message.edit': MessageEditData;
@@ -1885,8 +2052,8 @@ export type WsEventMap = {
1885
2052
  'approval.update': ApprovalUpdateData; // deprecated, kept for backward compat
1886
2053
  'card.update': CardUpdateData;
1887
2054
  'recovery.overflow': RecoveryOverflowData;
1888
- 'watching': WatchingData;
1889
- 'pong': { ts: number };
2055
+ watching: WatchingData;
2056
+ pong: { ts: number };
1890
2057
  'membership.changed': MembershipChangedData;
1891
2058
  'task.created': TaskCreatedData;
1892
2059
  'task.updated': TaskUpdatedData;
@@ -1905,6 +2072,8 @@ export type WsEventMap = {
1905
2072
  'invitation.accepted': InvitationAcceptedEventData;
1906
2073
  'invitation.declined': InvitationDeclinedEventData;
1907
2074
  'invitation.revoked': InvitationRevokedEventData;
2075
+ 'org.join_request.new': OrgJoinRequestNewEventData;
2076
+ 'org.invite_link.joined': OrgInviteLinkJoinedEventData;
1908
2077
  'agent_config.update': AgentConfigUpdateData;
1909
2078
  'presence.update': PresenceUpdateData;
1910
2079
  'wiki.changeset.created': WikiChangesetCreatedData;
@@ -1918,6 +2087,7 @@ export type WsEventMap = {
1918
2087
  'inbox.bulk_update': InboxBulkUpdateData;
1919
2088
  'read_position.updated': ReadPositionUpdateData;
1920
2089
  'dispatch.new': DispatchNewData;
2090
+ 'dispatch.received': DispatchReceivedData;
1921
2091
  'schedule.created': ScheduleCreatedData;
1922
2092
  'schedule.updated': ScheduleUpdatedData;
1923
2093
  'schedule.deleted': ScheduleDeletedData;
@@ -1934,6 +2104,11 @@ export type WsEventMap = {
1934
2104
  'machine.workspace.setup.requested': MachineWorkspaceSetupRequestedData;
1935
2105
  'machine.stop': MachineStopData;
1936
2106
  'machine.filesystem.browse': MachineFilesystemBrowseData;
2107
+ 'machine.update': MachineUpdateData;
2108
+ 'machine.clip.install': MachineClipInstallData;
2109
+ 'clip.installed': ClipInstalledData;
2110
+ 'clip.removed': ClipRemovedData;
2111
+ 'clip.updated': ClipUpdatedData;
1937
2112
  'agent.new_session': AgentNewSessionData;
1938
2113
  };
1939
2114
 
@@ -1966,6 +2141,25 @@ export interface InvitationRevokedEventData {
1966
2141
  org_id: string;
1967
2142
  }
1968
2143
 
2144
+ /** Fan-out to org admins when an end-user submits a join-request via the
2145
+ * shareable org invite link. Mirrors the payload published by
2146
+ * publishJoinRequested in server/internal/api/handler/org_invite_link.go. */
2147
+ export interface OrgJoinRequestNewEventData {
2148
+ join_request_id: string;
2149
+ org_id: string;
2150
+ user_id: string;
2151
+ display_name: string;
2152
+ created_at: string;
2153
+ }
2154
+
2155
+ export interface OrgInviteLinkJoinedEventData {
2156
+ org_id: string;
2157
+ user_id: string;
2158
+ display_name: string;
2159
+ role: OrgMemberRole;
2160
+ source: 'invite_link';
2161
+ }
2162
+
1969
2163
  // ============================================================
1970
2164
  // Platform Config Types
1971
2165
  // ============================================================
@@ -2186,7 +2380,17 @@ export interface CreditWallet {
2186
2380
  export interface CreditTransaction {
2187
2381
  id: string;
2188
2382
  org_id: string;
2189
- type: 'topup' | 'auto_reload' | 'llm_deduct' | 'compute_deduct' | 'compute_hold' | 'compute_settle' | 'adjustment' | 'refund' | 'grant' | 'grant_expire';
2383
+ type:
2384
+ | 'topup'
2385
+ | 'auto_reload'
2386
+ | 'llm_deduct'
2387
+ | 'compute_deduct'
2388
+ | 'compute_hold'
2389
+ | 'compute_settle'
2390
+ | 'adjustment'
2391
+ | 'refund'
2392
+ | 'grant'
2393
+ | 'grant_expire';
2190
2394
  amount: number;
2191
2395
  balance_after: number;
2192
2396
  grant_id: string | null;
@@ -2343,3 +2547,132 @@ export interface BillingMachineStoppedEvent {
2343
2547
  export interface BillingInsufficientEvent {
2344
2548
  org_id: string;
2345
2549
  }
2550
+
2551
+ // ============================================================
2552
+ // Clip Types
2553
+ // ============================================================
2554
+
2555
+ export type ClipSourceType = 'registry' | 'custom' | 'builtin';
2556
+ export type ClipStatus = 'active' | 'disabled';
2557
+
2558
+ export interface Clip {
2559
+ id: string;
2560
+ org_id: string;
2561
+ alias: string;
2562
+ name: string;
2563
+ description: string | null;
2564
+ manifest: Record<string, unknown>;
2565
+ source_type: ClipSourceType;
2566
+ source_ref: string | null;
2567
+ version: string | null;
2568
+ status: ClipStatus;
2569
+ created_by: string | null;
2570
+ /** Registry clip that reconciles onto every org machine, including machines
2571
+ * that join after creation. Targeted installs leave this false and persist
2572
+ * per-machine pending clip_instances instead. */
2573
+ install_on_all_machines: boolean;
2574
+ created_at: string;
2575
+ updated_at: string;
2576
+ }
2577
+
2578
+ export interface AgentClip {
2579
+ agent_id: string;
2580
+ clip_id: string;
2581
+ config: Record<string, unknown> | null;
2582
+ created_at: string;
2583
+ }
2584
+
2585
+ export interface CreateClipRequest {
2586
+ alias: string;
2587
+ name: string;
2588
+ description?: string;
2589
+ manifest: Record<string, unknown>;
2590
+ source_type?: ClipSourceType;
2591
+ source_ref?: string;
2592
+ version?: string;
2593
+ target_machine_ids?: string[];
2594
+ }
2595
+
2596
+ export interface UpdateClipRequest {
2597
+ name?: string;
2598
+ description?: string;
2599
+ manifest?: Record<string, unknown>;
2600
+ status?: ClipStatus;
2601
+ version?: string;
2602
+ }
2603
+
2604
+ export interface BindAgentClipRequest {
2605
+ clip_id: string;
2606
+ config?: Record<string, unknown>;
2607
+ }
2608
+
2609
+ export interface InvokeClipRequest {
2610
+ alias: string;
2611
+ command: string;
2612
+ input?: unknown;
2613
+ timeout_ms?: number;
2614
+ }
2615
+
2616
+ export interface InvokeClipResponse {
2617
+ output: unknown;
2618
+ error: string | null;
2619
+ }
2620
+
2621
+ export type ClipInstanceStatus = 'pending' | 'installed' | 'running' | 'stopped' | 'error';
2622
+
2623
+ export interface ClipInstance {
2624
+ id: string;
2625
+ clip_id: string;
2626
+ machine_id: string | null;
2627
+ status: ClipInstanceStatus;
2628
+ version: string | null;
2629
+ error_msg: string | null;
2630
+ last_seen: string | null;
2631
+ created_at: string;
2632
+ updated_at: string;
2633
+ }
2634
+
2635
+ export interface OnlineClipInfo {
2636
+ alias: string;
2637
+ name: string;
2638
+ version: string;
2639
+ commands: Array<{ name: string; description: string }>;
2640
+ provider_name: string;
2641
+ }
2642
+
2643
+ // Durable install reconcile — a registry clip the machine should install.
2644
+ export interface MachineClipInstall {
2645
+ clip_id: string;
2646
+ alias: string;
2647
+ source_ref?: string;
2648
+ version?: string;
2649
+ }
2650
+
2651
+ // Pinix registry catalog clip info (from GET /clip/v1/registry/clips,
2652
+ // which proxies the public Pinix registry GET /search).
2653
+ export interface RegistryCommandInfo {
2654
+ name: string;
2655
+ description: string;
2656
+ input?: string;
2657
+ output?: string;
2658
+ }
2659
+
2660
+ export interface RegistryClipInfo {
2661
+ name: string; // @scope/name (canonical package id)
2662
+ package: string; // @scope/name (alias derivation + install source_ref)
2663
+ version: string;
2664
+ type: string; // registry package type (e.g. "clip")
2665
+ description?: string;
2666
+ domain?: string;
2667
+ author?: string;
2668
+ commands: RegistryCommandInfo[];
2669
+ dependencies: string[];
2670
+ }
2671
+
2672
+ // Clip WS event data types
2673
+ export type ClipInstalledData = Clip;
2674
+ export type ClipUpdatedData = Clip;
2675
+ export interface ClipRemovedData {
2676
+ clip_id: string;
2677
+ org_id: string;
2678
+ }
package/src/ws.ts CHANGED
@@ -5,9 +5,9 @@ export type WsEventType = keyof WsEventMap;
5
5
  export type WsEventHandler<T extends WsEventType> = (data: WsEventMap[T], seq?: number) => void;
6
6
 
7
7
  export type WsClientEventMap = {
8
- 'ping': { ts: number };
9
- 'typing': { chat_id: string; thread_root_id: string | null; action: 'start' | 'stop' };
10
- 'watch': { chat_ids: string[] };
8
+ ping: { ts: number };
9
+ typing: { chat_id: string; thread_root_id: string | null; action: 'start' | 'stop' };
10
+ watch: { chat_ids: string[] };
11
11
  'agent.heartbeat': { session_id: string; telemetry?: Record<string, unknown> };
12
12
  };
13
13
 
@@ -26,10 +26,10 @@ export interface ParallWsOptions {
26
26
 
27
27
  function isRetryableNetworkError(err: unknown): boolean {
28
28
  return (
29
- err instanceof Error
30
- && err.name === 'ApiError'
31
- && 'status' in err
32
- && (err as { status?: unknown }).status === 0
29
+ err instanceof Error &&
30
+ err.name === 'ApiError' &&
31
+ 'status' in err &&
32
+ (err as { status?: unknown }).status === 0
33
33
  );
34
34
  }
35
35
 
@@ -39,7 +39,11 @@ function isBrowserRuntime(): boolean {
39
39
 
40
40
  export class ParallWs {
41
41
  private ws: WebSocket | null = null;
42
- private options: ParallWsOptions & { reconnect: boolean; reconnectInterval: number; maxReconnectInterval: number };
42
+ private options: ParallWsOptions & {
43
+ reconnect: boolean;
44
+ reconnectInterval: number;
45
+ maxReconnectInterval: number;
46
+ };
43
47
  private listeners = new Map<string, Set<WsEventHandler<WsEventType>>>();
44
48
  private stateListeners = new Set<(state: WsConnectionState) => void>();
45
49
  private heartbeatTimer: ReturnType<typeof setInterval> | null = null;
@@ -115,7 +119,11 @@ export class ParallWs {
115
119
  ws.onclose = null;
116
120
  ws.onopen = null;
117
121
  ws.onerror = null;
118
- try { ws.close(); } catch { /* ignore */ }
122
+ try {
123
+ ws.close();
124
+ } catch {
125
+ /* ignore */
126
+ }
119
127
  // Only reconnect if this socket is still the active one.
120
128
  // If connect() was called again, a newer socket owns the lifecycle.
121
129
  if (ws !== this.ws) return;
@@ -271,7 +279,10 @@ export class ParallWs {
271
279
  // event-loop stalls. Probe with a 5s timeout rather than force-
272
280
  // reconnecting, so healthy connections that were merely timer-starved
273
281
  // survive while genuinely dead sockets are caught quickly.
274
- if (this.lastReceivedAt > 0 && Date.now() - this.lastReceivedAt > this.heartbeatIntervalMs * 1.5) {
282
+ if (
283
+ this.lastReceivedAt > 0 &&
284
+ Date.now() - this.lastReceivedAt > this.heartbeatIntervalMs * 1.5
285
+ ) {
275
286
  this.probeConnection();
276
287
  return;
277
288
  }
@@ -320,7 +331,11 @@ export class ParallWs {
320
331
  this.ws.onopen = null;
321
332
  this.ws.onerror = null;
322
333
  this.ws.onmessage = null;
323
- try { this.ws.close(); } catch { /* ignore */ }
334
+ try {
335
+ this.ws.close();
336
+ } catch {
337
+ /* ignore */
338
+ }
324
339
  this.ws = null;
325
340
  }
326
341
  if (this.options.reconnect && !this.intentionalClose) {