@love-moon/conductor-sdk 0.6.0 → 0.7.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/CHANGELOG.md +8 -0
- package/dist/api/index.d.ts +1 -1
- package/dist/api/shared.d.ts +1 -1
- package/dist/api/tasks.d.ts +68 -0
- package/dist/api/tasks.js +113 -0
- package/dist/backend/client.d.ts +9 -0
- package/dist/backend/client.js +31 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
package/dist/api/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { ProjectsApi, type Project, type CreateProjectInput, type ListProjectsOptions, type ResolveProjectInput, } from './projects.js';
|
|
2
2
|
export { IssuesApi, type Issue, type ListIssuesInput, type CreateIssueInput, type UpdateIssueInput, type UpdateIssueStatusOptions, } from './issues.js';
|
|
3
|
-
export { TasksApi, type Task, type Message, type ListTasksInput, type SendTaskMessageOptions, type ListTaskMessagesOptions, } from './tasks.js';
|
|
3
|
+
export { TasksApi, type Task, type Message, type ListTasksInput, type SendTaskMessageOptions, type ListTaskMessagesOptions, type ScheduledMessage, type ScheduledMessageSchedule, type CreateScheduledMessageInput, } from './tasks.js';
|
|
4
4
|
export { ProjectNotResolvedError, buildAuditMetadata, isBackendApiError, type ApiClient, type SdkClientOptions, } from './shared.js';
|
package/dist/api/shared.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BackendApiClient, BackendApiError } from '../backend/index.js';
|
|
2
|
-
export type ApiClient = Pick<BackendApiClient, 'listProjects' | 'createProject' | 'getProject' | 'updateProject' | 'patchProjectByQuery' | 'setDefaultProject' | 'matchProjectByPath' | 'listIssues' | 'getIssue' | 'createIssue' | 'patchIssue' | 'deleteIssue' | 'listTasks' | 'getTask' | 'listTaskMessages' | 'postTaskMessage'>;
|
|
2
|
+
export type ApiClient = Pick<BackendApiClient, 'listProjects' | 'createProject' | 'getProject' | 'updateProject' | 'patchProjectByQuery' | 'setDefaultProject' | 'matchProjectByPath' | 'listIssues' | 'getIssue' | 'createIssue' | 'patchIssue' | 'deleteIssue' | 'listTasks' | 'getTask' | 'listTaskMessages' | 'postTaskMessage' | 'postTaskInsert' | 'listScheduledMessages' | 'createScheduledMessage' | 'deleteScheduledMessage'>;
|
|
3
3
|
export interface SdkClientOptions {
|
|
4
4
|
/**
|
|
5
5
|
* Optional override for the SDK version stamped onto audit metadata. Falls
|
package/dist/api/tasks.d.ts
CHANGED
|
@@ -21,6 +21,51 @@ export interface Message {
|
|
|
21
21
|
createdAt?: string | null;
|
|
22
22
|
raw: Record<string, unknown>;
|
|
23
23
|
}
|
|
24
|
+
export type ScheduledMessageSchedule = {
|
|
25
|
+
mode: 'delay';
|
|
26
|
+
amount: number;
|
|
27
|
+
unit: 'minute' | 'hour';
|
|
28
|
+
} | {
|
|
29
|
+
mode: 'at';
|
|
30
|
+
sendAt: string;
|
|
31
|
+
timezone?: string | null;
|
|
32
|
+
} | {
|
|
33
|
+
mode: 'interval';
|
|
34
|
+
every: number;
|
|
35
|
+
unit: 'minute' | 'hour';
|
|
36
|
+
condition?: 'none' | 'ai_idle';
|
|
37
|
+
stop?: {
|
|
38
|
+
maxRuns?: number | null;
|
|
39
|
+
maxSkips?: number | null;
|
|
40
|
+
stopAt?: string | null;
|
|
41
|
+
stopWhenTaskNotRunning?: boolean | null;
|
|
42
|
+
} | null;
|
|
43
|
+
};
|
|
44
|
+
export interface ScheduledMessage {
|
|
45
|
+
id: string;
|
|
46
|
+
userId?: string | null;
|
|
47
|
+
taskId: string;
|
|
48
|
+
sourceMessageId?: string | null;
|
|
49
|
+
content: string;
|
|
50
|
+
kind: string;
|
|
51
|
+
condition: string;
|
|
52
|
+
intervalMs?: number | null;
|
|
53
|
+
timezone?: string | null;
|
|
54
|
+
status: string;
|
|
55
|
+
nextRunAt: string;
|
|
56
|
+
runCount: number;
|
|
57
|
+
skipCount: number;
|
|
58
|
+
failureCount: number;
|
|
59
|
+
maxRuns?: number | null;
|
|
60
|
+
maxSkips?: number | null;
|
|
61
|
+
stopAt?: string | null;
|
|
62
|
+
stopWhenTaskNotRunning: boolean;
|
|
63
|
+
lastRunAt?: string | null;
|
|
64
|
+
lastError?: string | null;
|
|
65
|
+
createdAt?: string | null;
|
|
66
|
+
updatedAt?: string | null;
|
|
67
|
+
raw: Record<string, unknown>;
|
|
68
|
+
}
|
|
24
69
|
export interface ListTasksInput {
|
|
25
70
|
projectId?: string;
|
|
26
71
|
issueId?: string;
|
|
@@ -31,10 +76,23 @@ export interface SendTaskMessageOptions {
|
|
|
31
76
|
metadata?: Record<string, unknown>;
|
|
32
77
|
clientRequestId?: string;
|
|
33
78
|
}
|
|
79
|
+
export interface InsertTaskMessageOptions {
|
|
80
|
+
metadata?: Record<string, unknown>;
|
|
81
|
+
/**
|
|
82
|
+
* The reply target of the in-flight turn to interrupt. When omitted, the
|
|
83
|
+
* server resolves the most recent user message as the target.
|
|
84
|
+
*/
|
|
85
|
+
targetReplyTo?: string;
|
|
86
|
+
}
|
|
34
87
|
export interface ListTaskMessagesOptions {
|
|
35
88
|
limit?: number;
|
|
36
89
|
before?: string;
|
|
37
90
|
}
|
|
91
|
+
export interface CreateScheduledMessageInput {
|
|
92
|
+
content: string;
|
|
93
|
+
schedule: ScheduledMessageSchedule;
|
|
94
|
+
sourceMessageId?: string | null;
|
|
95
|
+
}
|
|
38
96
|
export declare class TasksApi {
|
|
39
97
|
private readonly client;
|
|
40
98
|
private readonly options;
|
|
@@ -42,5 +100,15 @@ export declare class TasksApi {
|
|
|
42
100
|
listTasks(input?: ListTasksInput): Promise<Task[]>;
|
|
43
101
|
getTask(taskId: string): Promise<Task>;
|
|
44
102
|
sendTaskMessage(taskId: string, content: string, options?: SendTaskMessageOptions): Promise<Message>;
|
|
103
|
+
/**
|
|
104
|
+
* Insert a mid-turn message into a running task. The message is delivered and
|
|
105
|
+
* the in-flight turn is interrupted so the inserted message runs next, instead
|
|
106
|
+
* of being queued until the current turn finishes (which is what
|
|
107
|
+
* {@link sendTaskMessage} does).
|
|
108
|
+
*/
|
|
109
|
+
insertTaskMessage(taskId: string, content: string, options?: InsertTaskMessageOptions): Promise<Message>;
|
|
45
110
|
listTaskMessages(taskId: string, options?: ListTaskMessagesOptions): Promise<Message[]>;
|
|
111
|
+
listScheduledMessages(taskId: string): Promise<ScheduledMessage[]>;
|
|
112
|
+
createScheduledMessage(taskId: string, input: CreateScheduledMessageInput): Promise<ScheduledMessage>;
|
|
113
|
+
deleteScheduledMessage(taskId: string, scheduleId: string): Promise<void>;
|
|
46
114
|
}
|
package/dist/api/tasks.js
CHANGED
|
@@ -43,6 +43,53 @@ const normalizeMessage = (payload) => {
|
|
|
43
43
|
raw: payload,
|
|
44
44
|
};
|
|
45
45
|
};
|
|
46
|
+
const normalizeNumber = (value, fallback = 0) => {
|
|
47
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
if (typeof value === 'string' && value.trim()) {
|
|
51
|
+
const parsed = Number(value);
|
|
52
|
+
if (Number.isFinite(parsed)) {
|
|
53
|
+
return parsed;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return fallback;
|
|
57
|
+
};
|
|
58
|
+
const normalizeScheduledMessage = (payload) => {
|
|
59
|
+
const id = payload.id ? String(payload.id) : '';
|
|
60
|
+
if (!id) {
|
|
61
|
+
throw new Error('Scheduled message payload missing id');
|
|
62
|
+
}
|
|
63
|
+
const taskId = payload.taskId ?? payload.task_id;
|
|
64
|
+
if (!taskId) {
|
|
65
|
+
throw new Error('Scheduled message payload missing taskId');
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
id,
|
|
69
|
+
userId: payload.userId ?? payload.user_id ?? null,
|
|
70
|
+
taskId: String(taskId),
|
|
71
|
+
sourceMessageId: payload.sourceMessageId ?? payload.source_message_id ?? null,
|
|
72
|
+
content: typeof payload.content === 'string' ? payload.content : '',
|
|
73
|
+
kind: String(payload.kind ?? ''),
|
|
74
|
+
condition: String(payload.condition ?? 'none'),
|
|
75
|
+
intervalMs: payload.intervalMs ?? payload.interval_ms ?? null,
|
|
76
|
+
timezone: payload.timezone ?? null,
|
|
77
|
+
status: String(payload.status ?? ''),
|
|
78
|
+
nextRunAt: String(payload.nextRunAt ?? payload.next_run_at ?? ''),
|
|
79
|
+
runCount: normalizeNumber(payload.runCount ?? payload.run_count),
|
|
80
|
+
skipCount: normalizeNumber(payload.skipCount ?? payload.skip_count),
|
|
81
|
+
failureCount: normalizeNumber(payload.failureCount ?? payload.failure_count),
|
|
82
|
+
maxRuns: payload.maxRuns ?? payload.max_runs ?? null,
|
|
83
|
+
maxSkips: payload.maxSkips ?? payload.max_skips ?? null,
|
|
84
|
+
stopAt: payload.stopAt ?? payload.stop_at ?? null,
|
|
85
|
+
stopWhenTaskNotRunning: Boolean(payload.stopWhenTaskNotRunning ?? payload.stop_when_task_not_running),
|
|
86
|
+
lastRunAt: payload.lastRunAt ?? payload.last_run_at ?? null,
|
|
87
|
+
lastError: payload.lastError ?? payload.last_error ?? null,
|
|
88
|
+
createdAt: payload.createdAt ?? payload.created_at ?? null,
|
|
89
|
+
updatedAt: payload.updatedAt ?? payload.updated_at ?? null,
|
|
90
|
+
raw: payload,
|
|
91
|
+
};
|
|
92
|
+
};
|
|
46
93
|
export class TasksApi {
|
|
47
94
|
client;
|
|
48
95
|
options;
|
|
@@ -104,6 +151,31 @@ export class TasksApi {
|
|
|
104
151
|
const payload = await this.client.postTaskMessage(trimmed, body);
|
|
105
152
|
return normalizeMessage(payload);
|
|
106
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* Insert a mid-turn message into a running task. The message is delivered and
|
|
156
|
+
* the in-flight turn is interrupted so the inserted message runs next, instead
|
|
157
|
+
* of being queued until the current turn finishes (which is what
|
|
158
|
+
* {@link sendTaskMessage} does).
|
|
159
|
+
*/
|
|
160
|
+
async insertTaskMessage(taskId, content, options = {}) {
|
|
161
|
+
const trimmed = String(taskId ?? '').trim();
|
|
162
|
+
if (!trimmed) {
|
|
163
|
+
throw new Error('taskId is required');
|
|
164
|
+
}
|
|
165
|
+
if (typeof content !== 'string' || content.length === 0) {
|
|
166
|
+
throw new Error('content is required');
|
|
167
|
+
}
|
|
168
|
+
const metadata = buildAuditMetadata(options.metadata, this.options);
|
|
169
|
+
const body = {
|
|
170
|
+
content,
|
|
171
|
+
metadata,
|
|
172
|
+
};
|
|
173
|
+
if (options.targetReplyTo) {
|
|
174
|
+
body.target_reply_to = options.targetReplyTo;
|
|
175
|
+
}
|
|
176
|
+
const payload = await this.client.postTaskInsert(trimmed, body);
|
|
177
|
+
return normalizeMessage(payload.message ?? payload);
|
|
178
|
+
}
|
|
107
179
|
async listTaskMessages(taskId, options = {}) {
|
|
108
180
|
const trimmed = String(taskId ?? '').trim();
|
|
109
181
|
if (!trimmed) {
|
|
@@ -115,4 +187,45 @@ export class TasksApi {
|
|
|
115
187
|
});
|
|
116
188
|
return messages.map((entry) => normalizeMessage(entry));
|
|
117
189
|
}
|
|
190
|
+
async listScheduledMessages(taskId) {
|
|
191
|
+
const trimmed = String(taskId ?? '').trim();
|
|
192
|
+
if (!trimmed) {
|
|
193
|
+
throw new Error('taskId is required');
|
|
194
|
+
}
|
|
195
|
+
const schedules = await this.client.listScheduledMessages(trimmed);
|
|
196
|
+
return schedules.map((entry) => normalizeScheduledMessage(entry));
|
|
197
|
+
}
|
|
198
|
+
async createScheduledMessage(taskId, input) {
|
|
199
|
+
const trimmed = String(taskId ?? '').trim();
|
|
200
|
+
if (!trimmed) {
|
|
201
|
+
throw new Error('taskId is required');
|
|
202
|
+
}
|
|
203
|
+
const content = typeof input?.content === 'string' ? input.content.trim() : '';
|
|
204
|
+
if (!content) {
|
|
205
|
+
throw new Error('content is required');
|
|
206
|
+
}
|
|
207
|
+
if (!input?.schedule || typeof input.schedule !== 'object') {
|
|
208
|
+
throw new Error('schedule is required');
|
|
209
|
+
}
|
|
210
|
+
const body = {
|
|
211
|
+
content,
|
|
212
|
+
schedule: input.schedule,
|
|
213
|
+
};
|
|
214
|
+
if (Object.prototype.hasOwnProperty.call(input, 'sourceMessageId')) {
|
|
215
|
+
body.sourceMessageId = input.sourceMessageId ?? null;
|
|
216
|
+
}
|
|
217
|
+
const schedule = await this.client.createScheduledMessage(trimmed, body);
|
|
218
|
+
return normalizeScheduledMessage(schedule);
|
|
219
|
+
}
|
|
220
|
+
async deleteScheduledMessage(taskId, scheduleId) {
|
|
221
|
+
const trimmedTaskId = String(taskId ?? '').trim();
|
|
222
|
+
const trimmedScheduleId = String(scheduleId ?? '').trim();
|
|
223
|
+
if (!trimmedTaskId) {
|
|
224
|
+
throw new Error('taskId is required');
|
|
225
|
+
}
|
|
226
|
+
if (!trimmedScheduleId) {
|
|
227
|
+
throw new Error('scheduleId is required');
|
|
228
|
+
}
|
|
229
|
+
await this.client.deleteScheduledMessage(trimmedTaskId, trimmedScheduleId);
|
|
230
|
+
}
|
|
118
231
|
}
|
package/dist/backend/client.d.ts
CHANGED
|
@@ -216,6 +216,15 @@ export declare class BackendApiClient {
|
|
|
216
216
|
* endpoint directly here. (RFC 0025 §2 picks the simpler path.)
|
|
217
217
|
*/
|
|
218
218
|
postTaskMessage(taskId: string, params: Record<string, unknown>): Promise<Record<string, any>>;
|
|
219
|
+
/**
|
|
220
|
+
* POST /tasks/[taskId]/insert — insert a mid-turn message. Unlike
|
|
221
|
+
* {@link postTaskMessage}, which queues a message for after the current turn,
|
|
222
|
+
* this interrupts the running turn so the inserted message is processed next.
|
|
223
|
+
*/
|
|
224
|
+
postTaskInsert(taskId: string, params: Record<string, unknown>): Promise<Record<string, any>>;
|
|
225
|
+
listScheduledMessages(taskId: string): Promise<Record<string, any>[]>;
|
|
226
|
+
createScheduledMessage(taskId: string, params: Record<string, unknown>): Promise<Record<string, any>>;
|
|
227
|
+
deleteScheduledMessage(taskId: string, scheduleId: string): Promise<void>;
|
|
219
228
|
private request;
|
|
220
229
|
private buildUrl;
|
|
221
230
|
private sendRequest;
|
package/dist/backend/client.js
CHANGED
|
@@ -410,6 +410,37 @@ export class BackendApiClient {
|
|
|
410
410
|
});
|
|
411
411
|
return this.parseJson(response);
|
|
412
412
|
}
|
|
413
|
+
/**
|
|
414
|
+
* POST /tasks/[taskId]/insert — insert a mid-turn message. Unlike
|
|
415
|
+
* {@link postTaskMessage}, which queues a message for after the current turn,
|
|
416
|
+
* this interrupts the running turn so the inserted message is processed next.
|
|
417
|
+
*/
|
|
418
|
+
async postTaskInsert(taskId, params) {
|
|
419
|
+
const response = await this.request('POST', `/tasks/${taskId}/insert`, {
|
|
420
|
+
body: JSON.stringify(params),
|
|
421
|
+
});
|
|
422
|
+
return this.parseJson(response);
|
|
423
|
+
}
|
|
424
|
+
async listScheduledMessages(taskId) {
|
|
425
|
+
const response = await this.request('GET', `/tasks/${taskId}/scheduled-messages`);
|
|
426
|
+
const payload = await this.parseJson(response);
|
|
427
|
+
if (payload && typeof payload === 'object' && Array.isArray(payload.schedules)) {
|
|
428
|
+
return payload.schedules;
|
|
429
|
+
}
|
|
430
|
+
if (Array.isArray(payload)) {
|
|
431
|
+
return payload;
|
|
432
|
+
}
|
|
433
|
+
throw new BackendApiError('Invalid scheduled messages response', response.status, payload);
|
|
434
|
+
}
|
|
435
|
+
async createScheduledMessage(taskId, params) {
|
|
436
|
+
const response = await this.request('POST', `/tasks/${taskId}/scheduled-messages`, {
|
|
437
|
+
body: JSON.stringify(params),
|
|
438
|
+
});
|
|
439
|
+
return this.parseJson(response);
|
|
440
|
+
}
|
|
441
|
+
async deleteScheduledMessage(taskId, scheduleId) {
|
|
442
|
+
await this.request('DELETE', `/tasks/${taskId}/scheduled-messages/${scheduleId}`);
|
|
443
|
+
}
|
|
413
444
|
async request(method, pathname, opts = {}) {
|
|
414
445
|
const url = this.buildUrl(pathname, opts.query);
|
|
415
446
|
const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@love-moon/conductor-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/lovemoon-ai/conductor.git"
|
|
@@ -33,5 +33,5 @@
|
|
|
33
33
|
"typescript": "^5.6.3",
|
|
34
34
|
"vitest": "^2.1.4"
|
|
35
35
|
},
|
|
36
|
-
"gitCommitId": "
|
|
36
|
+
"gitCommitId": "ed4e3ab"
|
|
37
37
|
}
|