@controlflow-ai/daemon 0.1.1 → 0.1.3
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/README.md +66 -24
- package/package.json +16 -3
- package/src/agent-avatar.ts +30 -0
- package/src/agent-key.ts +28 -0
- package/src/agent-permissions.ts +359 -0
- package/src/agent-runtime.ts +810 -28
- package/src/agent-workspace.ts +183 -0
- package/src/app.ts +2183 -79
- package/src/args.ts +54 -7
- package/src/cli.ts +873 -14
- package/src/client.ts +482 -12
- package/src/coco.ts +9 -40
- package/src/codex.ts +33 -5
- package/src/config.ts +28 -4
- package/src/console.ts +460 -26
- package/src/daemon-client.ts +116 -3
- package/src/daemon.ts +958 -101
- package/src/db.ts +3216 -113
- package/src/delivery-ws.ts +269 -0
- package/src/format.ts +4 -1
- package/src/lark/app-registration.ts +141 -0
- package/src/lark/cli.ts +7 -137
- package/src/lark/credentials.ts +36 -3
- package/src/lark/event-router.ts +61 -5
- package/src/lark/inbound-events.ts +156 -3
- package/src/lark/server-integration.ts +659 -111
- package/src/lark/setup.ts +74 -5
- package/src/lark/ws-daemon.ts +136 -10
- package/src/local-api.ts +611 -14
- package/src/local-auth.ts +36 -3
- package/src/message-attachments.ts +71 -0
- package/src/messaging-cli.ts +741 -0
- package/src/messaging-status.ts +669 -0
- package/src/migrations/023_projects.ts +65 -0
- package/src/migrations/024_agents_model.ts +10 -0
- package/src/migrations/025_room_archive.ts +44 -0
- package/src/migrations/026_project_archive.ts +44 -0
- package/src/migrations/027_agent_permission_profiles.ts +16 -0
- package/src/migrations/028_lark_websocket_restart_state.ts +16 -0
- package/src/migrations/029_held_message_drafts.ts +32 -0
- package/src/migrations/030_agent_room_read_state.ts +25 -0
- package/src/migrations/031_room_tasks.ts +29 -0
- package/src/migrations/032_room_reminders.ts +29 -0
- package/src/migrations/033_room_saved_messages.ts +25 -0
- package/src/migrations/034_agent_activity_events.ts +27 -0
- package/src/migrations/035_agent_avatars.ts +17 -0
- package/src/migrations/036_project_agent_defaults.ts +21 -0
- package/src/migrations/037_message_attachments.ts +36 -0
- package/src/migrations/038_agent_activity_room_scope.ts +64 -0
- package/src/migrations/039_message_attachments_path.ts +34 -0
- package/src/migrations/040_message_attachments_file_schema.ts +80 -0
- package/src/migrations/041_room_system_events.ts +30 -0
- package/src/migrations/042_message_attachment_file_kind.ts +52 -0
- package/src/migrations/043_room_mode_skill_registry.ts +92 -0
- package/src/migrations/044_workflow_runtime.ts +69 -0
- package/src/migrations/045_skill_repository_ownership.ts +64 -0
- package/src/migrations.ts +70 -1
- package/src/neeko.ts +40 -4
- package/src/runtime-env.ts +179 -0
- package/src/runtime-registry.ts +83 -13
- package/src/server.ts +244 -4
- package/src/token-file.ts +13 -6
- package/src/types.ts +394 -0
- package/src/workflow-runtime.ts +275 -0
- package/src/web.ts +0 -904
package/src/client.ts
CHANGED
|
@@ -1,6 +1,73 @@
|
|
|
1
1
|
import { defaultServerToken, defaultServerUrl } from './config.js';
|
|
2
|
+
import { HttpError } from './http.js';
|
|
2
3
|
import { serverAuthHeaders } from './server-auth.js';
|
|
3
|
-
import type { AgentRoomSubscriptionMode, AgentRun, AgentSession, ApiResponse, Chat, Computer, ComputerAgentAssignment, ComputerConnection, DaemonInstance, Message, MessageDelivery, ProvisionedComputer, RoomChannel, RoomParticipant, RunAction } from './types.js';
|
|
4
|
+
import type { AgentActivityEvent, AgentActivityKind, AgentDeletionResult, AgentPermissionProfile, AgentRoomSubscription, AgentRoomSubscriptionMode, AgentRun, AgentSession, AgentWorkbench, ApiResponse, Chat, Computer, ComputerAgentAssignment, ComputerConnection, ComputerDeletionImpact, ComputerDeletionResult, DaemonInstance, DeliveryContext, EnabledSkill, HeldDraftStatus, HeldMessageDraft, Message, MessageDelivery, MessageFreshnessInput, ProvisionedComputer, RemoteFileList, RoomChannel, RoomParticipant, RoomReminder, RoomReminderStatus, RoomSavedMessage, RoomTask, RoomTaskStatus, RunAction } from './types.js';
|
|
5
|
+
export type { DeliveryBacklogSummary, DeliveryConnectionStats as DeliveryConnectionStatus, DeliveryWebSocketSummary, LarkMessagingStatus, MessagingDiagnostic, MessagingHealth, MessagingHealthDomain, MessagingStatus, MessagingStatusSummary } from './messaging-status.js';
|
|
6
|
+
import type { DeliveryBacklogSummary, DeliveryConnectionStats as DeliveryConnectionStatus, MessagingHealth, MessagingStatus } from './messaging-status.js';
|
|
7
|
+
|
|
8
|
+
export interface LarkRestartResult {
|
|
9
|
+
bots: string[];
|
|
10
|
+
restarted: string[];
|
|
11
|
+
missing: string[];
|
|
12
|
+
skipped_recent?: string[];
|
|
13
|
+
skipped_ineffective?: string[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface LarkProbeEventResult {
|
|
17
|
+
app_id: string;
|
|
18
|
+
envelope: string;
|
|
19
|
+
raw_event_id: string;
|
|
20
|
+
inserted: boolean;
|
|
21
|
+
duplicate: boolean;
|
|
22
|
+
parse_ok: 0 | 1;
|
|
23
|
+
handled: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface LarkRecentEventSummary {
|
|
27
|
+
id: string;
|
|
28
|
+
received_at: string;
|
|
29
|
+
app_id: string;
|
|
30
|
+
event_type: string;
|
|
31
|
+
event_id: string;
|
|
32
|
+
parse_ok: 0 | 1;
|
|
33
|
+
bytes: number;
|
|
34
|
+
is_probe: boolean;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface LarkRepairParseResult {
|
|
38
|
+
dry_run: boolean;
|
|
39
|
+
scanned: number;
|
|
40
|
+
repaired: number;
|
|
41
|
+
unchanged: number;
|
|
42
|
+
conflicts: number;
|
|
43
|
+
errors: number;
|
|
44
|
+
rows: Array<{
|
|
45
|
+
id: string;
|
|
46
|
+
app_id: string;
|
|
47
|
+
old_event_id: string;
|
|
48
|
+
old_event_type: string;
|
|
49
|
+
new_event_id: string;
|
|
50
|
+
new_event_type: string;
|
|
51
|
+
status: 'repaired' | 'would_repair' | 'unchanged' | 'conflict' | 'error';
|
|
52
|
+
error?: string;
|
|
53
|
+
}>;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface DeliveryProbeResult {
|
|
57
|
+
message: Message;
|
|
58
|
+
deliveries: MessageDelivery[];
|
|
59
|
+
notify: {
|
|
60
|
+
deliveries: number;
|
|
61
|
+
target_connections: number;
|
|
62
|
+
open_sockets: number;
|
|
63
|
+
websocket_frames: number;
|
|
64
|
+
};
|
|
65
|
+
probe: {
|
|
66
|
+
token: string;
|
|
67
|
+
agent: string;
|
|
68
|
+
room: string;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
4
71
|
|
|
5
72
|
export interface SendRequest {
|
|
6
73
|
chat?: string;
|
|
@@ -15,6 +82,102 @@ export interface SendRequest {
|
|
|
15
82
|
type?: 'message' | 'system';
|
|
16
83
|
idempotency_key?: string | null;
|
|
17
84
|
mentions?: string[];
|
|
85
|
+
mention_lint?: 'strict' | 'literal' | 'infer';
|
|
86
|
+
attachments?: SendMessageAttachmentRequest[];
|
|
87
|
+
messages?: SendBatchMessageRequest[];
|
|
88
|
+
freshness?: MessageFreshnessInput;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface SendBatchMessageRequest {
|
|
92
|
+
parent_id?: number;
|
|
93
|
+
channel_id?: string | null;
|
|
94
|
+
recipient?: string | null;
|
|
95
|
+
content: string;
|
|
96
|
+
type?: 'message' | 'system';
|
|
97
|
+
idempotency_key?: string | null;
|
|
98
|
+
mentions?: string[];
|
|
99
|
+
attachments?: SendMessageAttachmentRequest[];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface SendMessageAttachmentRequest {
|
|
103
|
+
kind: 'image' | 'file';
|
|
104
|
+
mime_type: string;
|
|
105
|
+
filename?: string | null;
|
|
106
|
+
content_base64: string;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface SendBatchRequest extends Omit<SendRequest, 'content' | 'recipient' | 'mentions' | 'idempotency_key' | 'type' | 'parent_id' | 'channel_id'> {
|
|
110
|
+
messages: SendBatchMessageRequest[];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface SendMessageResult {
|
|
114
|
+
message?: Message;
|
|
115
|
+
messages?: Message[];
|
|
116
|
+
deliveries?: MessageDelivery[];
|
|
117
|
+
notify?: unknown;
|
|
118
|
+
draft?: HeldMessageDraft;
|
|
119
|
+
drafts?: HeldMessageDraft[];
|
|
120
|
+
intervening_messages?: Message[];
|
|
121
|
+
invalid_mentions?: string[];
|
|
122
|
+
available_mentions?: string[];
|
|
123
|
+
mention_lint?: {
|
|
124
|
+
missing_mentions: string[];
|
|
125
|
+
available_mentions: string[];
|
|
126
|
+
message: string;
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export interface HeldDraftResolutionResult {
|
|
131
|
+
draft: HeldMessageDraft;
|
|
132
|
+
message?: Message;
|
|
133
|
+
deliveries?: MessageDelivery[];
|
|
134
|
+
notify?: unknown;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export interface ListHeldDraftsRequest {
|
|
138
|
+
agent?: string;
|
|
139
|
+
room_id?: string | null;
|
|
140
|
+
status?: HeldDraftStatus | 'all';
|
|
141
|
+
limit?: number;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface CreateRoomTasksRequest {
|
|
145
|
+
title?: string;
|
|
146
|
+
tasks?: Array<{ title: string }>;
|
|
147
|
+
created_by?: string | null;
|
|
148
|
+
source_message_id?: number | null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface CreateRoomReminderRequest {
|
|
152
|
+
msg_id: number;
|
|
153
|
+
title: string;
|
|
154
|
+
created_by?: string | null;
|
|
155
|
+
fire_at?: string | null;
|
|
156
|
+
delay_seconds?: number | null;
|
|
157
|
+
repeat?: string | null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export interface ListRoomRemindersRequest {
|
|
161
|
+
status?: RoomReminderStatus | 'all';
|
|
162
|
+
created_by?: string | null;
|
|
163
|
+
room_id?: string | null;
|
|
164
|
+
limit?: number;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export interface CreateRoomSavedMessageRequest {
|
|
168
|
+
msg_id: number;
|
|
169
|
+
saved_by: string;
|
|
170
|
+
note?: string | null;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export interface ListRoomSavedMessagesRequest {
|
|
174
|
+
saved_by?: string | null;
|
|
175
|
+
room_id?: string | null;
|
|
176
|
+
limit?: number;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export interface ClaimRoomTaskRequest {
|
|
180
|
+
assignee: string;
|
|
18
181
|
}
|
|
19
182
|
|
|
20
183
|
export interface DaemonAuth {
|
|
@@ -65,6 +228,15 @@ export interface ProvisionComputerRequest {
|
|
|
65
228
|
package_name?: string;
|
|
66
229
|
}
|
|
67
230
|
|
|
231
|
+
export interface UpdateComputerRequest {
|
|
232
|
+
name: string;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export interface RegenerateComputerCommandRequest {
|
|
236
|
+
server_url?: string;
|
|
237
|
+
package_name?: string;
|
|
238
|
+
}
|
|
239
|
+
|
|
68
240
|
export interface CreateDeliveryRequest {
|
|
69
241
|
message_id: number;
|
|
70
242
|
agent: string;
|
|
@@ -75,6 +247,7 @@ export interface ClaimDeliveryRequest {
|
|
|
75
247
|
connection_id?: string | null;
|
|
76
248
|
computer_id?: string | null;
|
|
77
249
|
lease_ms?: number;
|
|
250
|
+
steer_run_id?: string | null;
|
|
78
251
|
}
|
|
79
252
|
|
|
80
253
|
export interface GetOrCreateSessionRequest {
|
|
@@ -106,6 +279,23 @@ export interface FinishRunRequest {
|
|
|
106
279
|
output?: string;
|
|
107
280
|
}
|
|
108
281
|
|
|
282
|
+
export interface RecordAgentActivityRequest {
|
|
283
|
+
kind: AgentActivityKind;
|
|
284
|
+
title: string;
|
|
285
|
+
detail?: string | null;
|
|
286
|
+
metadata?: Record<string, unknown> | null;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export interface CreateHandoffRoomRequest {
|
|
290
|
+
source_room_id: string;
|
|
291
|
+
source_message_id?: number;
|
|
292
|
+
actor: string;
|
|
293
|
+
purpose: string;
|
|
294
|
+
name: string;
|
|
295
|
+
team?: Array<{ agent: string; mode?: AgentRoomSubscriptionMode }>;
|
|
296
|
+
handoff_content?: string;
|
|
297
|
+
}
|
|
298
|
+
|
|
109
299
|
export interface CreateArtifactRequest {
|
|
110
300
|
content_base64: string;
|
|
111
301
|
mime_type: string;
|
|
@@ -132,13 +322,17 @@ export class LockClient {
|
|
|
132
322
|
return data.chats;
|
|
133
323
|
}
|
|
134
324
|
|
|
135
|
-
async listRooms(): Promise<Chat[]> {
|
|
136
|
-
const
|
|
325
|
+
async listRooms(agentScope?: string): Promise<Chat[]> {
|
|
326
|
+
const params = new URLSearchParams();
|
|
327
|
+
if (agentScope) params.set('agent_scope', agentScope);
|
|
328
|
+
const data = await this.get<{ rooms: Chat[] }>(`/api/rooms${params.size ? `?${params}` : ''}`);
|
|
137
329
|
return data.rooms;
|
|
138
330
|
}
|
|
139
331
|
|
|
140
|
-
async listRoomMembers(room: string): Promise<{ room: Chat; participants: RoomParticipant[]; completeness: string }> {
|
|
141
|
-
const
|
|
332
|
+
async listRoomMembers(room: string, agent?: string): Promise<{ room: Chat; participants: RoomParticipant[]; agent_subscriptions?: AgentRoomSubscription[]; enabled_skills?: EnabledSkill[]; completeness: string }> {
|
|
333
|
+
const params = new URLSearchParams();
|
|
334
|
+
if (agent) params.set('agent', agent);
|
|
335
|
+
const data = await this.get<{ room: Chat; participants: RoomParticipant[]; agent_subscriptions?: AgentRoomSubscription[]; enabled_skills?: EnabledSkill[]; completeness: string }>(`/api/rooms/${encodeURIComponent(room)}/members${params.size ? `?${params}` : ''}`);
|
|
142
336
|
return data;
|
|
143
337
|
}
|
|
144
338
|
|
|
@@ -146,32 +340,183 @@ export class LockClient {
|
|
|
146
340
|
return this.post<{ participant: RoomParticipant; subscription: unknown }>(`/api/rooms/${encodeURIComponent(room)}/agents`, input);
|
|
147
341
|
}
|
|
148
342
|
|
|
343
|
+
async createHandoffRoom(input: CreateHandoffRoomRequest): Promise<{ room: Chat; message: Message | null; deliveries: MessageDelivery[]; notify: unknown }> {
|
|
344
|
+
return this.post<{ room: Chat; message: Message | null; deliveries: MessageDelivery[]; notify: unknown }>('/api/rooms/handoff', input);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
async leaveAgentRoom(room: string, agent: string): Promise<{ room: Chat; agent: string; participant_removed: boolean; subscriptions_removed: number; active_deliveries_canceled: number }> {
|
|
348
|
+
return this.delete<{ room: Chat; agent: string; participant_removed: boolean; subscriptions_removed: number; active_deliveries_canceled: number }>(`/api/rooms/${encodeURIComponent(room)}/agents/${encodeURIComponent(agent)}`);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
async deleteAgent(agent: string, input: { confirm_delete: boolean; leave_rooms: boolean; unbind_lark: boolean } = { confirm_delete: true, leave_rooms: true, unbind_lark: true }): Promise<{ deletion: AgentDeletionResult; lark: { unbound: boolean; app_id: string | null; error: string | null } }> {
|
|
352
|
+
return this.delete<{ deletion: AgentDeletionResult; lark: { unbound: boolean; app_id: string | null; error: string | null } }>(`/api/agents/${encodeURIComponent(agent)}`, undefined, input);
|
|
353
|
+
}
|
|
354
|
+
|
|
149
355
|
async createTopic(room: string, input: { name: string; created_by?: string | null }): Promise<RoomChannel> {
|
|
150
356
|
const data = await this.post<{ channel: RoomChannel }>(`/api/rooms/${encodeURIComponent(room)}/topics`, input);
|
|
151
357
|
return data.channel;
|
|
152
358
|
}
|
|
153
359
|
|
|
360
|
+
async listRoomTasks(room: string, status: RoomTaskStatus | 'all' = 'all', limit = 50): Promise<RoomTask[]> {
|
|
361
|
+
const params = new URLSearchParams({ status, limit: String(limit) });
|
|
362
|
+
const data = await this.get<{ tasks: RoomTask[] }>(`/api/rooms/${encodeURIComponent(room)}/tasks?${params}`);
|
|
363
|
+
return data.tasks;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
async createRoomTasks(room: string, input: CreateRoomTasksRequest): Promise<RoomTask[]> {
|
|
367
|
+
const data = await this.post<{ tasks: RoomTask[] }>(`/api/rooms/${encodeURIComponent(room)}/tasks`, input);
|
|
368
|
+
return data.tasks;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
async claimRoomTask(room: string, taskNumber: number, input: ClaimRoomTaskRequest): Promise<RoomTask> {
|
|
372
|
+
const data = await this.post<{ task: RoomTask }>(`/api/rooms/${encodeURIComponent(room)}/tasks/${taskNumber}/claim`, input);
|
|
373
|
+
return data.task;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
async unclaimRoomTask(room: string, taskNumber: number): Promise<RoomTask> {
|
|
377
|
+
const data = await this.post<{ task: RoomTask }>(`/api/rooms/${encodeURIComponent(room)}/tasks/${taskNumber}/unclaim`, {});
|
|
378
|
+
return data.task;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
async updateRoomTaskStatus(room: string, taskNumber: number, status: RoomTaskStatus): Promise<RoomTask> {
|
|
382
|
+
const data = await this.patch<{ task: RoomTask }>(`/api/rooms/${encodeURIComponent(room)}/tasks/${taskNumber}`, { status });
|
|
383
|
+
return data.task;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
async restartRoomAgent(room: string, agent: string): Promise<AgentRun> {
|
|
387
|
+
const data = await this.post<{ run: AgentRun }>(`/api/rooms/${encodeURIComponent(room)}/agents/${encodeURIComponent(agent)}/restart`, {});
|
|
388
|
+
return data.run;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
async scheduleReminder(input: CreateRoomReminderRequest): Promise<RoomReminder> {
|
|
392
|
+
const data = await this.post<{ reminder: RoomReminder }>('/api/reminders', input);
|
|
393
|
+
return data.reminder;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
async listReminders(input: ListRoomRemindersRequest = {}): Promise<RoomReminder[]> {
|
|
397
|
+
const params = new URLSearchParams();
|
|
398
|
+
params.set('status', input.status ?? 'scheduled');
|
|
399
|
+
if (input.created_by) params.set('created_by', input.created_by);
|
|
400
|
+
if (input.room_id) params.set('room_id', input.room_id);
|
|
401
|
+
params.set('limit', String(input.limit ?? 50));
|
|
402
|
+
const data = await this.get<{ reminders: RoomReminder[] }>(`/api/reminders?${params}`);
|
|
403
|
+
return data.reminders;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
async cancelReminder(id: string): Promise<RoomReminder> {
|
|
407
|
+
const data = await this.post<{ reminder: RoomReminder }>(`/api/reminders/${encodeURIComponent(id)}/cancel`, {});
|
|
408
|
+
return data.reminder;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
async saveMessage(input: CreateRoomSavedMessageRequest): Promise<RoomSavedMessage> {
|
|
412
|
+
const data = await this.post<{ saved_message: RoomSavedMessage }>('/api/saved-messages', input);
|
|
413
|
+
return data.saved_message;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
async listSavedMessages(input: ListRoomSavedMessagesRequest = {}): Promise<RoomSavedMessage[]> {
|
|
417
|
+
const params = new URLSearchParams();
|
|
418
|
+
if (input.saved_by) params.set('saved_by', input.saved_by);
|
|
419
|
+
if (input.room_id) params.set('room_id', input.room_id);
|
|
420
|
+
params.set('limit', String(input.limit ?? 50));
|
|
421
|
+
const data = await this.get<{ saved_messages: RoomSavedMessage[] }>(`/api/saved-messages?${params}`);
|
|
422
|
+
return data.saved_messages;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
async removeSavedMessage(id: string): Promise<RoomSavedMessage> {
|
|
426
|
+
const data = await this.post<{ saved_message: RoomSavedMessage }>(`/api/saved-messages/${encodeURIComponent(id)}/delete`, {});
|
|
427
|
+
return data.saved_message;
|
|
428
|
+
}
|
|
429
|
+
|
|
154
430
|
async getMessages(params: URLSearchParams): Promise<Message[]> {
|
|
155
431
|
const data = await this.get<{ messages: Message[] }>(`/api/messages?${params}`);
|
|
156
432
|
return data.messages;
|
|
157
433
|
}
|
|
158
434
|
|
|
435
|
+
async getDeliveryContext(input: { agent: string; chatId: string; messageId: number; limit?: number }): Promise<DeliveryContext> {
|
|
436
|
+
const params = new URLSearchParams({
|
|
437
|
+
agent: input.agent,
|
|
438
|
+
chat_id: input.chatId,
|
|
439
|
+
message_id: String(input.messageId),
|
|
440
|
+
limit: String(input.limit ?? 50),
|
|
441
|
+
});
|
|
442
|
+
const data = await this.get<{ context: DeliveryContext }>(`/api/messages/context?${params}`);
|
|
443
|
+
return data.context;
|
|
444
|
+
}
|
|
445
|
+
|
|
159
446
|
async getInbox(agent: string, after = 0, limit = 50): Promise<Message[]> {
|
|
160
447
|
const params = new URLSearchParams({ agent, after: String(after), limit: String(limit) });
|
|
161
448
|
const data = await this.get<{ messages: Message[] }>(`/api/inbox?${params}`);
|
|
162
449
|
return data.messages;
|
|
163
450
|
}
|
|
164
451
|
|
|
165
|
-
async getMessage(id: number): Promise<Message> {
|
|
166
|
-
const
|
|
452
|
+
async getMessage(id: number, agentScope?: string): Promise<Message> {
|
|
453
|
+
const suffix = agentScope ? `?agent_scope=${encodeURIComponent(agentScope)}` : '';
|
|
454
|
+
const data = await this.get<{ message: Message }>(`/api/messages/${id}${suffix}`);
|
|
167
455
|
return data.message;
|
|
168
456
|
}
|
|
169
457
|
|
|
458
|
+
async getMessageAttachmentContent(id: string, agentScope?: string): Promise<{ content: Uint8Array; mimeType: string; filename: string }> {
|
|
459
|
+
const suffix = agentScope ? `?agent_scope=${encodeURIComponent(agentScope)}` : '';
|
|
460
|
+
const response = await fetch(`${this.baseUrl}/api/message-attachments/${encodeURIComponent(id)}/content${suffix}`);
|
|
461
|
+
if (!response.ok) {
|
|
462
|
+
let message = `request failed: ${response.status}`;
|
|
463
|
+
let code = 'REQUEST_FAILED';
|
|
464
|
+
try {
|
|
465
|
+
const payload = await response.json() as ApiResponse<unknown>;
|
|
466
|
+
if ('code' in payload && typeof payload.code === 'string') code = payload.code;
|
|
467
|
+
message = payload.message ?? message;
|
|
468
|
+
} catch {
|
|
469
|
+
// Binary endpoint errors should be JSON, but keep a fallback.
|
|
470
|
+
}
|
|
471
|
+
throw new HttpError(response.status, code, message);
|
|
472
|
+
}
|
|
473
|
+
const filename = response.headers.get('content-disposition')?.match(/filename="([^"]+)"/)?.[1] ?? id;
|
|
474
|
+
return {
|
|
475
|
+
content: new Uint8Array(await response.arrayBuffer()),
|
|
476
|
+
mimeType: response.headers.get('content-type') ?? 'application/octet-stream',
|
|
477
|
+
filename,
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
|
|
170
481
|
async sendMessage(input: SendRequest): Promise<Message> {
|
|
171
|
-
const data = await this.
|
|
482
|
+
const data = await this.sendMessageResult(input);
|
|
483
|
+
if (!data.message) throw new HttpError(202, 'MESSAGE_HELD', 'message was held as a draft');
|
|
172
484
|
return data.message;
|
|
173
485
|
}
|
|
174
486
|
|
|
487
|
+
async sendMessageResult(input: SendRequest): Promise<SendMessageResult> {
|
|
488
|
+
return this.post<SendMessageResult>('/api/messages', input);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
async getAgentWorkbench(agent: string): Promise<AgentWorkbench> {
|
|
492
|
+
const data = await this.get<{ workbench: AgentWorkbench }>(`/api/agents/${encodeURIComponent(agent)}/workbench`);
|
|
493
|
+
return data.workbench;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
async listHeldDrafts(input: ListHeldDraftsRequest = {}): Promise<HeldMessageDraft[]> {
|
|
497
|
+
const agent = input.agent?.trim();
|
|
498
|
+
if (!agent) throw new Error('agent is required');
|
|
499
|
+
const workbench = await this.getAgentWorkbench(agent);
|
|
500
|
+
const status = input.status ?? 'held';
|
|
501
|
+
const limit = input.limit ?? 50;
|
|
502
|
+
return workbench.held_drafts
|
|
503
|
+
.filter((draft) => status === 'all' || draft.status === status)
|
|
504
|
+
.filter((draft) => !input.room_id || draft.chat_id === input.room_id)
|
|
505
|
+
.slice(0, limit);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
async abandonHeldDraft(id: string): Promise<HeldDraftResolutionResult> {
|
|
509
|
+
return this.post<HeldDraftResolutionResult>(`/api/held-drafts/${encodeURIComponent(id)}/abandon`, {});
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
async sendHeldDraftAnyway(id: string): Promise<HeldDraftResolutionResult> {
|
|
513
|
+
return this.post<HeldDraftResolutionResult>(`/api/held-drafts/${encodeURIComponent(id)}/send-anyway`, {});
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
async reviseHeldDraft(id: string, content: string): Promise<HeldDraftResolutionResult> {
|
|
517
|
+
return this.post<HeldDraftResolutionResult>(`/api/held-drafts/${encodeURIComponent(id)}/revise`, { content });
|
|
518
|
+
}
|
|
519
|
+
|
|
175
520
|
async provisionComputer(input: ProvisionComputerRequest = {}): Promise<ProvisionedComputer> {
|
|
176
521
|
const data = await this.post<ProvisionedComputer>('/api/computers/provision', input);
|
|
177
522
|
return data;
|
|
@@ -182,8 +527,39 @@ export class LockClient {
|
|
|
182
527
|
return data.computers;
|
|
183
528
|
}
|
|
184
529
|
|
|
185
|
-
async
|
|
186
|
-
const data = await this.
|
|
530
|
+
async updateComputer(computerId: string, input: UpdateComputerRequest): Promise<Computer> {
|
|
531
|
+
const data = await this.patch<{ computer: Computer }>(`/api/computers/${encodeURIComponent(computerId)}`, input);
|
|
532
|
+
return data.computer;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
async regenerateComputerCommand(computerId: string, input: RegenerateComputerCommandRequest = {}): Promise<ProvisionedComputer> {
|
|
536
|
+
return this.post<ProvisionedComputer>(`/api/computers/${encodeURIComponent(computerId)}/reconnect-command`, input);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
async getComputerDeleteImpact(computerId: string): Promise<ComputerDeletionImpact> {
|
|
540
|
+
const data = await this.get<{ impact: ComputerDeletionImpact }>(`/api/computers/${encodeURIComponent(computerId)}/delete-impact`);
|
|
541
|
+
return data.impact;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
async deleteComputer(computerId: string, input: { remove_projects?: boolean; remove_agents?: boolean } = {}): Promise<ComputerDeletionResult & { deleted: boolean }> {
|
|
545
|
+
return this.delete<ComputerDeletionResult & { deleted: boolean }>(`/api/computers/${encodeURIComponent(computerId)}`, undefined, input);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
async fetchPermissionProfile(agent: string): Promise<AgentPermissionProfile> {
|
|
549
|
+
const data = await this.get<{ profile: AgentPermissionProfile }>(`/api/agents/${encodeURIComponent(agent)}/permissions`);
|
|
550
|
+
return data.profile;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
async connectComputer(input: ConnectComputerRequest): Promise<{ computer: Computer; connection: ComputerConnection; token: string; local_control_token?: string; daemon: DaemonInstance; agents: ComputerAgentAssignment[] }> {
|
|
554
|
+
const data = await this.post<{ computer: Computer; connection: ComputerConnection; token: string; local_control_token?: string; daemon: DaemonInstance; agents: ComputerAgentAssignment[] }>('/api/computers/connect', input);
|
|
555
|
+
return data;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
async listComputerFiles(computerId: string, input: { path?: string; show_hidden?: boolean } = {}): Promise<RemoteFileList> {
|
|
559
|
+
const params = new URLSearchParams();
|
|
560
|
+
if (input.path) params.set('path', input.path);
|
|
561
|
+
if (input.show_hidden) params.set('show_hidden', 'true');
|
|
562
|
+
const data = await this.get<RemoteFileList>(`/api/computers/${encodeURIComponent(computerId)}/files${params.size ? `?${params}` : ''}`);
|
|
187
563
|
return data;
|
|
188
564
|
}
|
|
189
565
|
|
|
@@ -197,12 +573,80 @@ export class LockClient {
|
|
|
197
573
|
return data.daemon;
|
|
198
574
|
}
|
|
199
575
|
|
|
200
|
-
async listDeliveries(agent: string, status = 'pending', limit = 50): Promise<MessageDelivery[]> {
|
|
576
|
+
async listDeliveries(agent: string, status = 'pending', limit = 50, options: { distinctChat?: boolean; excludeRunningComputerId?: string | null; connectionId?: string | null } = {}): Promise<MessageDelivery[]> {
|
|
201
577
|
const params = new URLSearchParams({ agent, status, limit: String(limit) });
|
|
578
|
+
if (options.distinctChat) params.set('distinct_chat', 'true');
|
|
579
|
+
if (options.excludeRunningComputerId) params.set('exclude_running_computer_id', options.excludeRunningComputerId);
|
|
580
|
+
if (options.connectionId) params.set('connection_id', options.connectionId);
|
|
202
581
|
const data = await this.get<{ deliveries: MessageDelivery[] }>(`/api/deliveries?${params}`);
|
|
203
582
|
return data.deliveries;
|
|
204
583
|
}
|
|
205
584
|
|
|
585
|
+
async getDelivery(id: string): Promise<MessageDelivery> {
|
|
586
|
+
const data = await this.get<{ delivery: MessageDelivery }>(`/api/deliveries/${encodeURIComponent(id)}`);
|
|
587
|
+
return data.delivery;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
async listPendingDeliveryAgents(): Promise<Array<{ agent: string; pending: number }>> {
|
|
591
|
+
const data = await this.get<{ agents: Array<{ agent: string; pending: number }> }>('/api/deliveries/pending-agents');
|
|
592
|
+
return data.agents;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
async listDeliveryBacklog(): Promise<DeliveryBacklogSummary[]> {
|
|
596
|
+
const data = await this.get<{ backlog: DeliveryBacklogSummary[] }>('/api/deliveries/backlog');
|
|
597
|
+
return data.backlog;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
async getDeliveryWebSocketStatus(): Promise<DeliveryConnectionStatus> {
|
|
601
|
+
const data = await this.get<{ websocket: DeliveryConnectionStatus }>('/api/daemon/ws/status');
|
|
602
|
+
return data.websocket;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
async getMessagingStatus(): Promise<MessagingStatus> {
|
|
606
|
+
return this.get<MessagingStatus>('/api/messaging/status');
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
async getMessagingHealth(): Promise<MessagingHealth> {
|
|
610
|
+
return this.get<MessagingHealth>('/api/messaging/health');
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
async probeDelivery(input: { agent?: string; room?: string; sender?: string; content?: string; idempotencyKey?: string | null } = {}, token = defaultServerToken()): Promise<DeliveryProbeResult> {
|
|
614
|
+
return this.post<DeliveryProbeResult>('/api/messaging/probe-delivery', {
|
|
615
|
+
agent: input.agent,
|
|
616
|
+
room: input.room,
|
|
617
|
+
sender: input.sender,
|
|
618
|
+
content: input.content,
|
|
619
|
+
idempotency_key: input.idempotencyKey,
|
|
620
|
+
}, serverAuthHeaders(token));
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
async restartLarkWebSocket(options: { appId?: string; appIds?: string[] } = {}): Promise<LarkRestartResult> {
|
|
624
|
+
const body = options.appId ? { app_id: options.appId } : options.appIds ? { app_ids: options.appIds } : {};
|
|
625
|
+
return this.post<LarkRestartResult>('/api/lark/restart', body);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
async probeLarkEvent(input: { appId: string; envelope?: string; data: unknown }, token = defaultServerToken()): Promise<LarkProbeEventResult> {
|
|
629
|
+
return this.post<LarkProbeEventResult>('/api/lark/probe-event', {
|
|
630
|
+
app_id: input.appId,
|
|
631
|
+
envelope: input.envelope,
|
|
632
|
+
data: input.data,
|
|
633
|
+
}, serverAuthHeaders(token));
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
async listRecentLarkEvents(limit = 20): Promise<LarkRecentEventSummary[]> {
|
|
637
|
+
const params = new URLSearchParams({ limit: String(limit) });
|
|
638
|
+
const data = await this.get<{ events: LarkRecentEventSummary[] }>(`/api/lark/events/recent?${params}`);
|
|
639
|
+
return data.events;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
async repairLarkEventParseFailures(input: { appId?: string; limit?: number; dryRun?: boolean } = {}, token = defaultServerToken()): Promise<LarkRepairParseResult> {
|
|
643
|
+
return this.post<LarkRepairParseResult>('/api/lark/events/repair-parse', {
|
|
644
|
+
app_id: input.appId,
|
|
645
|
+
limit: input.limit,
|
|
646
|
+
dry_run: input.dryRun,
|
|
647
|
+
}, serverAuthHeaders(token));
|
|
648
|
+
}
|
|
649
|
+
|
|
206
650
|
async createDelivery(input: CreateDeliveryRequest): Promise<MessageDelivery> {
|
|
207
651
|
const data = await this.post<{ delivery: MessageDelivery }>('/api/deliveries', input);
|
|
208
652
|
return data.delivery;
|
|
@@ -218,6 +662,11 @@ export class LockClient {
|
|
|
218
662
|
return data.delivery;
|
|
219
663
|
}
|
|
220
664
|
|
|
665
|
+
async markDeliveryProcessingCompleted(id: string, input: FinishDeliveryRequest): Promise<MessageDelivery> {
|
|
666
|
+
const data = await this.post<{ delivery: MessageDelivery }>(`/api/deliveries/${id}/processing-completed`, input);
|
|
667
|
+
return data.delivery;
|
|
668
|
+
}
|
|
669
|
+
|
|
221
670
|
async getOrCreateSession(input: GetOrCreateSessionRequest): Promise<AgentSession> {
|
|
222
671
|
const data = await this.post<{ session: AgentSession }>('/api/sessions', input);
|
|
223
672
|
return data.session;
|
|
@@ -263,6 +712,11 @@ export class LockClient {
|
|
|
263
712
|
return data.run;
|
|
264
713
|
}
|
|
265
714
|
|
|
715
|
+
async recordRunActivity(runId: string, input: RecordAgentActivityRequest): Promise<AgentActivityEvent> {
|
|
716
|
+
const data = await this.post<{ event: AgentActivityEvent }>(`/api/runs/${runId}/activity`, input);
|
|
717
|
+
return data.event;
|
|
718
|
+
}
|
|
719
|
+
|
|
266
720
|
async finishRun(runId: string, input: FinishRunRequest): Promise<AgentRun> {
|
|
267
721
|
const data = await this.post<{ run: AgentRun }>(`/api/runs/${runId}/finish`, input);
|
|
268
722
|
return data.run;
|
|
@@ -290,6 +744,22 @@ export class LockClient {
|
|
|
290
744
|
});
|
|
291
745
|
}
|
|
292
746
|
|
|
747
|
+
private async patch<T>(path: string, body: unknown, headers?: HeadersInit): Promise<T> {
|
|
748
|
+
return this.request<T>(path, {
|
|
749
|
+
method: 'PATCH',
|
|
750
|
+
headers: { 'content-type': 'application/json', ...this.daemonAuthHeaders(), ...headers },
|
|
751
|
+
body: JSON.stringify(body),
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
private async delete<T>(path: string, headers?: HeadersInit, body?: unknown): Promise<T> {
|
|
756
|
+
return this.request<T>(path, {
|
|
757
|
+
method: 'DELETE',
|
|
758
|
+
headers: { ...(body === undefined ? {} : { 'content-type': 'application/json' }), ...this.daemonAuthHeaders(), ...headers },
|
|
759
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
|
|
293
763
|
private daemonAuthHeaders(): HeadersInit {
|
|
294
764
|
if (!this.daemonAuth) return {};
|
|
295
765
|
return {
|
|
@@ -303,7 +773,7 @@ export class LockClient {
|
|
|
303
773
|
const response = await fetch(`${this.baseUrl}${path}`, init);
|
|
304
774
|
const payload = await response.json() as ApiResponse<T>;
|
|
305
775
|
if (!response.ok || !payload.ok) {
|
|
306
|
-
throw new
|
|
776
|
+
throw new HttpError(response.status, 'code' in payload && typeof payload.code === 'string' ? payload.code : 'REQUEST_FAILED', payload.message ?? `request failed: ${response.status}`);
|
|
307
777
|
}
|
|
308
778
|
return payload.data as T;
|
|
309
779
|
}
|
package/src/coco.ts
CHANGED
|
@@ -1,52 +1,21 @@
|
|
|
1
1
|
import { buildPalPrompt, runtimeCwd, type AgentRuntime, type AgentRuntimeRunInput } from './agent-runtime.js';
|
|
2
|
+
import { buildCocoPermissionArgs, buildRuntimeLaunchContext, effectivePermissionProfile } from './agent-permissions.js';
|
|
2
3
|
export { runAgentRuntime } from './agent-runtime.js';
|
|
3
4
|
|
|
4
|
-
function
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
try {
|
|
9
|
-
const event = JSON.parse(trimmed) as { session_id?: unknown };
|
|
10
|
-
if (typeof event.session_id === 'string' && event.session_id.trim()) {
|
|
11
|
-
return event.session_id;
|
|
12
|
-
}
|
|
13
|
-
} catch {
|
|
14
|
-
// Non-JSON stdout is kept in output; it just is not a JSONL event.
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function makeCocoRuntime(_agentUuid: string): AgentRuntime {
|
|
5
|
+
export function makeCocoRuntime(_agentUuid: string, model?: string | null): AgentRuntime {
|
|
6
|
+
// Coco ACP exits before initialize when passed --model. Per-invocation model
|
|
7
|
+
// selection works through config overrides.
|
|
8
|
+
const modelArgs = model?.trim() ? ['-c', `model.name=${model.trim()}`] : [];
|
|
21
9
|
return {
|
|
22
10
|
name: 'coco',
|
|
23
|
-
capabilities: { protocol: 'acp', resume: 'runtime-session-id', busyDeliveryMode: 'queue', supportsMcp: true },
|
|
24
|
-
command: 'coco',
|
|
25
|
-
buildPrompt: buildPalPrompt,
|
|
26
|
-
buildCwd: runtimeCwd,
|
|
27
|
-
buildArgs(input: AgentRuntimeRunInput): string[] {
|
|
28
|
-
return ['acp', 'serve', '-y', ...input.extraArgs];
|
|
29
|
-
},
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function makeCocoStreamJsonRuntime(_agentUuid: string): AgentRuntime {
|
|
34
|
-
return {
|
|
35
|
-
name: 'coco-stream-json',
|
|
36
|
-
capabilities: { protocol: 'json-stream', resume: 'runtime-session-id', busyDeliveryMode: 'queue', supportsMcp: false },
|
|
11
|
+
capabilities: { protocol: 'acp', resume: 'runtime-session-id', busyDeliveryMode: 'queue', supportsMcp: true, supportsSteer: false },
|
|
37
12
|
command: 'coco',
|
|
38
13
|
buildPrompt: buildPalPrompt,
|
|
39
14
|
buildCwd: runtimeCwd,
|
|
40
15
|
buildArgs(input: AgentRuntimeRunInput): string[] {
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
return ['
|
|
44
|
-
},
|
|
45
|
-
parseOutput({ stdout, stderr, input }) {
|
|
46
|
-
return {
|
|
47
|
-
output: [stdout.trim(), stderr.trim()].filter(Boolean).join('\n'),
|
|
48
|
-
runtimeSessionId: extractSessionId(stdout) ?? input.runtimeSessionId ?? null,
|
|
49
|
-
};
|
|
16
|
+
const context = input.launchContext ?? buildRuntimeLaunchContext(input);
|
|
17
|
+
const permissionArgs = buildCocoPermissionArgs(effectivePermissionProfile(input), context);
|
|
18
|
+
return ['acp', 'serve', ...permissionArgs, ...modelArgs, ...input.extraArgs];
|
|
50
19
|
},
|
|
51
20
|
};
|
|
52
21
|
}
|