@love-moon/conductor-sdk 0.2.16 → 0.2.18

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.
@@ -4,6 +4,30 @@ export interface BackendClientOptions {
4
4
  fetchImpl?: FetchFn;
5
5
  timeoutMs?: number;
6
6
  }
7
+ export type AgentCommitEvent = {
8
+ eventType: 'sdk_message';
9
+ taskId: string;
10
+ content: string;
11
+ metadata?: Record<string, unknown>;
12
+ messageId?: string | null;
13
+ } | {
14
+ eventType: 'task_status_update';
15
+ taskId: string;
16
+ status: string;
17
+ summary?: string | null;
18
+ statusEventId?: string | null;
19
+ } | {
20
+ eventType: 'agent_command_ack';
21
+ requestId: string;
22
+ taskId?: string | null;
23
+ accepted?: boolean;
24
+ commandEventType?: string | null;
25
+ } | {
26
+ eventType: 'task_stop_ack';
27
+ taskId: string;
28
+ requestId: string;
29
+ accepted?: boolean;
30
+ };
7
31
  export declare class BackendApiError extends Error {
8
32
  readonly statusCode?: number | undefined;
9
33
  readonly details?: unknown | undefined;
@@ -50,6 +74,7 @@ export declare class BackendApiClient {
50
74
  id?: string;
51
75
  projectId: string;
52
76
  title: string;
77
+ status?: string;
53
78
  backendType?: string;
54
79
  sessionId?: string | null;
55
80
  sessionFilePath?: string | null;
@@ -73,6 +98,39 @@ export declare class BackendApiClient {
73
98
  content: string;
74
99
  metadata?: Record<string, unknown>;
75
100
  }): Promise<any>;
101
+ commitAgentEvents(params: {
102
+ agentHost: string;
103
+ events: AgentCommitEvent[];
104
+ }): Promise<{
105
+ results: Array<Record<string, unknown>>;
106
+ }>;
107
+ commitSdkMessage(params: {
108
+ agentHost: string;
109
+ taskId: string;
110
+ content: string;
111
+ metadata?: Record<string, unknown>;
112
+ messageId?: string | null;
113
+ }): Promise<Record<string, unknown>>;
114
+ commitTaskStatusUpdate(params: {
115
+ agentHost: string;
116
+ taskId: string;
117
+ status: string;
118
+ summary?: string | null;
119
+ statusEventId?: string | null;
120
+ }): Promise<Record<string, unknown>>;
121
+ commitAgentCommandAck(params: {
122
+ agentHost: string;
123
+ requestId: string;
124
+ taskId?: string | null;
125
+ accepted?: boolean;
126
+ commandEventType?: string | null;
127
+ }): Promise<Record<string, unknown>>;
128
+ commitTaskStopAck(params: {
129
+ agentHost: string;
130
+ taskId: string;
131
+ requestId: string;
132
+ accepted?: boolean;
133
+ }): Promise<Record<string, unknown>>;
76
134
  matchProjectByPath(params: {
77
135
  hostname: string;
78
136
  path: string;
@@ -152,6 +152,108 @@ export class BackendApiClient {
152
152
  });
153
153
  return this.parseJson(response);
154
154
  }
155
+ async commitAgentEvents(params) {
156
+ const response = await this.request('POST', '/agent/events', {
157
+ body: JSON.stringify({
158
+ agent_host: params.agentHost,
159
+ events: params.events.map((event) => {
160
+ if (event.eventType === 'sdk_message') {
161
+ return {
162
+ event_type: event.eventType,
163
+ task_id: event.taskId,
164
+ content: event.content,
165
+ metadata: event.metadata,
166
+ message_id: event.messageId ?? undefined,
167
+ };
168
+ }
169
+ if (event.eventType === 'task_status_update') {
170
+ return {
171
+ event_type: event.eventType,
172
+ task_id: event.taskId,
173
+ status: event.status,
174
+ summary: event.summary ?? undefined,
175
+ status_event_id: event.statusEventId ?? undefined,
176
+ };
177
+ }
178
+ if (event.eventType === 'task_stop_ack') {
179
+ return {
180
+ event_type: event.eventType,
181
+ task_id: event.taskId,
182
+ request_id: event.requestId,
183
+ accepted: event.accepted !== false,
184
+ };
185
+ }
186
+ return {
187
+ event_type: event.eventType,
188
+ request_id: event.requestId,
189
+ task_id: event.taskId ?? undefined,
190
+ accepted: event.accepted !== false,
191
+ command_event_type: event.commandEventType ?? undefined,
192
+ };
193
+ }),
194
+ }),
195
+ });
196
+ return this.parseJson(response);
197
+ }
198
+ async commitSdkMessage(params) {
199
+ const payload = await this.commitAgentEvents({
200
+ agentHost: params.agentHost,
201
+ events: [
202
+ {
203
+ eventType: 'sdk_message',
204
+ taskId: params.taskId,
205
+ content: params.content,
206
+ metadata: params.metadata,
207
+ messageId: params.messageId,
208
+ },
209
+ ],
210
+ });
211
+ return (Array.isArray(payload.results) ? payload.results[0] : null) ?? {};
212
+ }
213
+ async commitTaskStatusUpdate(params) {
214
+ const payload = await this.commitAgentEvents({
215
+ agentHost: params.agentHost,
216
+ events: [
217
+ {
218
+ eventType: 'task_status_update',
219
+ taskId: params.taskId,
220
+ status: params.status,
221
+ summary: params.summary,
222
+ statusEventId: params.statusEventId,
223
+ },
224
+ ],
225
+ });
226
+ return (Array.isArray(payload.results) ? payload.results[0] : null) ?? {};
227
+ }
228
+ async commitAgentCommandAck(params) {
229
+ const payload = await this.commitAgentEvents({
230
+ agentHost: params.agentHost,
231
+ events: [
232
+ {
233
+ eventType: 'agent_command_ack',
234
+ requestId: params.requestId,
235
+ taskId: params.taskId,
236
+ accepted: params.accepted,
237
+ commandEventType: params.commandEventType,
238
+ },
239
+ ],
240
+ });
241
+ return (Array.isArray(payload.results) ? payload.results[0] : null) ?? {};
242
+ }
243
+ async commitTaskStopAck(params) {
244
+ const payload = await this.commitAgentEvents({
245
+ agentHost: params.agentHost,
246
+ events: [
247
+ {
248
+ eventType: 'task_stop_ack',
249
+ taskId: params.taskId,
250
+ requestId: params.requestId,
251
+ accepted: params.accepted,
252
+ },
253
+ ],
254
+ });
255
+ return (Array.isArray(payload.results) ? payload.results[0] : null) ?? {};
256
+ }
155
257
  async matchProjectByPath(params) {
156
258
  const response = await this.request('POST', '/projects/match-path', {
157
259
  body: JSON.stringify(params),
package/dist/client.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import { BackendApiClient } from './backend/index.js';
2
2
  import { ConductorConfig } from './config/index.js';
3
3
  import { MessageRouter } from './message/index.js';
4
+ import { DownstreamCursorStore, DurableUpstreamOutboxStore } from './outbox/index.js';
4
5
  import { SessionDiskStore, SessionManager } from './session/index.js';
5
- import { ConductorWebSocketClient } from './ws/index.js';
6
- type BackendApiLike = Pick<BackendApiClient, 'listProjects' | 'createProject' | 'listTasks' | 'createTask' | 'updateTask' | 'matchProjectByPath' | 'getProject' | 'updateProject'>;
6
+ import { ConductorWebSocketClient, WebSocketConnectedEvent, WebSocketDisconnectEvent } from './ws/index.js';
7
+ type BackendApiLike = Pick<BackendApiClient, 'listProjects' | 'createProject' | 'listTasks' | 'createTask' | 'updateTask' | 'commitSdkMessage' | 'commitTaskStatusUpdate' | 'commitAgentCommandAck' | 'commitTaskStopAck' | 'matchProjectByPath' | 'getProject' | 'updateProject'>;
7
8
  type RealtimeClientLike = Pick<ConductorWebSocketClient, 'registerHandler' | 'connect' | 'disconnect' | 'sendJson'>;
8
9
  export interface ConductorClientConnectOptions {
9
10
  config?: ConductorConfig;
@@ -11,27 +12,31 @@ export interface ConductorClientConnectOptions {
11
12
  env?: Record<string, string | undefined>;
12
13
  extraEnv?: Record<string, string | undefined>;
13
14
  projectPath?: string;
15
+ deliveryScopeId?: string;
14
16
  backendApi?: BackendApiLike;
15
17
  wsClient?: RealtimeClientLike;
16
18
  sessionManager?: SessionManager;
17
19
  sessionStore?: SessionDiskStore;
18
20
  messageRouter?: MessageRouter;
21
+ upstreamOutbox?: DurableUpstreamOutboxStore;
22
+ downstreamCursorStore?: DownstreamCursorStore;
19
23
  agentHost?: string;
20
- onConnected?: (event: {
21
- isReconnect: boolean;
22
- }) => void;
23
- onDisconnected?: () => void;
24
+ onConnected?: (event: WebSocketConnectedEvent) => void;
25
+ onDisconnected?: (event: WebSocketDisconnectEvent) => void;
24
26
  onStopTask?: (event: StopTaskEvent) => Promise<void> | void;
25
27
  }
26
28
  interface ConductorClientInit {
27
29
  config: ConductorConfig;
28
30
  env: Record<string, string | undefined>;
29
31
  projectPath: string;
32
+ deliveryScopeId: string;
30
33
  backendApi: BackendApiLike;
31
34
  wsClient: RealtimeClientLike;
32
35
  sessionManager: SessionManager;
33
36
  sessionStore: SessionDiskStore;
34
37
  messageRouter: MessageRouter;
38
+ upstreamOutbox: DurableUpstreamOutboxStore;
39
+ downstreamCursorStore: DownstreamCursorStore;
35
40
  agentHost: string;
36
41
  onStopTask?: (event: StopTaskEvent) => Promise<void> | void;
37
42
  }
@@ -49,11 +54,15 @@ export declare class ConductorClient {
49
54
  private readonly sessions;
50
55
  private readonly sessionStore;
51
56
  private readonly messageRouter;
57
+ private upstreamOutbox;
58
+ private downstreamCursorStore;
52
59
  private readonly agentHost;
53
60
  private readonly onStopTask?;
61
+ private deliveryScopeId;
54
62
  private closed;
55
- private pendingOutbound;
56
- private readonly ACK_TIMEOUT_MS;
63
+ private durableOutboxFlushPromise;
64
+ private durableOutboxTimer;
65
+ private durableOutboxTimerDueAt;
57
66
  constructor(init: ConductorClientInit);
58
67
  static connect(options?: ConductorClientConnectOptions): Promise<ConductorClient>;
59
68
  close(): Promise<void>;
@@ -65,6 +74,10 @@ export declare class ConductorClient {
65
74
  active_tasks?: string[];
66
75
  source?: string;
67
76
  metadata?: Record<string, any>;
77
+ last_applied_cursor?: {
78
+ created_at: string;
79
+ request_id: string;
80
+ };
68
81
  }): Promise<Record<string, any>>;
69
82
  sendAgentCommandAck(payload: {
70
83
  request_id: string;
@@ -88,28 +101,22 @@ export declare class ConductorClient {
88
101
  matchProjectByPath(payload?: Record<string, any>): Promise<Record<string, any>>;
89
102
  bindProjectPath(projectId: string, payload?: Record<string, any>): Promise<Record<string, any>>;
90
103
  private readonly handleBackendEvent;
91
- /**
92
- * Handle acknowledgment messages from backend for confirmable outbound messages
93
- */
94
- private handleAcknowledgment;
95
- /**
96
- * Send a confirmable message and wait for acknowledgment from backend.
97
- * Implements reliable delivery with idempotency.
98
- */
99
- private sendConfirmable;
100
- /**
101
- * Actually send a confirmable message over websocket.
102
- * Called initially and on reconnection.
103
- */
104
- private doSendConfirmable;
105
- /**
106
- * Flush all pending confirmable messages.
107
- * Called after websocket reconnection.
108
- */
109
- private flushPendingOutbound;
104
+ private extractDownstreamCommandContext;
105
+ private handleStopTaskCommand;
106
+ private invokeStopTaskHandler;
107
+ private persistAndCommitUpstreamEvent;
108
+ private requestDurableOutboxFlush;
109
+ private hasEarlierPendingSdkMessage;
110
+ private commitDurableUpstreamEvent;
111
+ private isRetryableUpstreamError;
112
+ private computeDurableOutboxRetryDelay;
113
+ private scheduleDurableOutboxFlush;
114
+ private clearDurableOutboxTimer;
110
115
  private sendEnvelope;
111
116
  private maybeAckInboundCommand;
112
- private handleStopTaskEvent;
117
+ private promoteTaskDeliveryScope;
118
+ private setDeliveryScopeId;
119
+ private shouldAutoFlushDurableOutbox;
113
120
  private resolveHostname;
114
121
  private waitForTaskCreation;
115
122
  private readIntEnv;