@parall/agent-core 1.26.1 → 1.26.2
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/event-format.d.ts.map +1 -1
- package/dist/event-format.js +7 -0
- package/dist/gateway-base.d.ts +1 -0
- package/dist/gateway-base.d.ts.map +1 -1
- package/dist/gateway-base.js +68 -3
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/event-format.ts +6 -0
- package/src/gateway-base.ts +63 -1
- package/src/types.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-format.d.ts","sourceRoot":"","sources":["../src/event-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAM1D,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"event-format.d.ts","sourceRoot":"","sources":["../src/event-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAM1D,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAsDzD;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAK/D;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,CASnE"}
|
package/dist/event-format.js
CHANGED
|
@@ -37,6 +37,13 @@ export function buildEventBody(event) {
|
|
|
37
37
|
lines.push(`[Comment ID: prll://${event.messageId}]`);
|
|
38
38
|
lines.push("", event.body);
|
|
39
39
|
}
|
|
40
|
+
else if (event.type === "approval") {
|
|
41
|
+
lines.push(`[Event: approval.decided]`);
|
|
42
|
+
lines.push(`[Approval: prll://${event.messageId}]`);
|
|
43
|
+
lines.push(`[Chat: prll://${event.targetId}]`);
|
|
44
|
+
lines.push(`[Decided by: ${event.senderName} (prll://${event.senderId})]`);
|
|
45
|
+
lines.push("", event.body);
|
|
46
|
+
}
|
|
40
47
|
else if (event.type === "schedule") {
|
|
41
48
|
lines.push(`[Event: schedule.fired]`);
|
|
42
49
|
lines.push(`[Schedule: prll://${event.targetId}]`);
|
package/dist/gateway-base.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway-base.d.ts","sourceRoot":"","sources":["../src/gateway-base.ts"],"names":[],"mappings":"AAIA,OAAO,EAAuB,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,KAAK,EACV,qBAAqB,
|
|
1
|
+
{"version":3,"file":"gateway-base.d.ts","sourceRoot":"","sources":["../src/gateway-base.ts"],"names":[],"mappings":"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"}
|
package/dist/gateway-base.js
CHANGED
|
@@ -192,6 +192,19 @@ export class ParallAgentGateway {
|
|
|
192
192
|
this.opts.log?.error(`parall[${this.opts.accountId}]: schedule fire dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
|
+
else if (data.event_type === "approval_decided") {
|
|
196
|
+
if (!data.source_id)
|
|
197
|
+
return;
|
|
198
|
+
try {
|
|
199
|
+
const dispatched = await this.fetchAndHandleApprovalDecided(data.source_id, data.actor_id, data.chat_id ?? null);
|
|
200
|
+
if (dispatched) {
|
|
201
|
+
this.opts.client.ackDispatchByID(this.opts.config.org_id, data.id).catch(() => { });
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
this.opts.log?.error(`parall[${this.opts.accountId}]: approval decided dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
195
208
|
else if (data.event_type !== "message" && data.event_type !== "task_assign") {
|
|
196
209
|
// Truly unknown event_type — log so a newly-added dispatch type
|
|
197
210
|
// not yet wired here surfaces during runtime testing. "message"
|
|
@@ -262,7 +275,7 @@ export class ParallAgentGateway {
|
|
|
262
275
|
runtimeType: this.opts.runtimeType,
|
|
263
276
|
runtimeKey: this.opts.runtimeKey,
|
|
264
277
|
sessionId: this.activeSessionId,
|
|
265
|
-
chatId: event.type === "message" ? event.targetId : undefined,
|
|
278
|
+
chatId: (event.type === "message" || event.type === "approval") ? event.targetId : undefined,
|
|
266
279
|
triggerMessageId: event.messageId,
|
|
267
280
|
noReply: event.noReply ?? false,
|
|
268
281
|
contextFilePath: this.opts.contextFilePathForSession?.(sessionKey),
|
|
@@ -284,11 +297,13 @@ export class ParallAgentGateway {
|
|
|
284
297
|
trigger_type: event.type === "task" ? "task_assign" :
|
|
285
298
|
event.type === "task_comment" ? "task_comment" :
|
|
286
299
|
event.type === "schedule" ? "schedule_fire" :
|
|
287
|
-
"
|
|
300
|
+
event.type === "approval" ? "approval_decided" :
|
|
301
|
+
"mention",
|
|
288
302
|
trigger_ref: event.type === "task" ? { task_id: event.targetId } :
|
|
289
303
|
event.type === "task_comment" ? { comment_id: event.messageId, task_id: event.targetId } :
|
|
290
304
|
event.type === "schedule" ? { schedule_id: event.targetId, run_id: event.messageId } :
|
|
291
|
-
{
|
|
305
|
+
event.type === "approval" ? { approval_id: event.messageId } :
|
|
306
|
+
{ message_id: event.messageId },
|
|
292
307
|
sender_id: event.senderId,
|
|
293
308
|
sender_name: event.senderName,
|
|
294
309
|
summary: event.body.substring(0, 200),
|
|
@@ -1059,6 +1074,53 @@ export class ParallAgentGateway {
|
|
|
1059
1074
|
}
|
|
1060
1075
|
return dispatched;
|
|
1061
1076
|
}
|
|
1077
|
+
async fetchAndHandleApprovalDecided(approvalId, actorId, chatId) {
|
|
1078
|
+
let approval = null;
|
|
1079
|
+
try {
|
|
1080
|
+
approval = await this.opts.client.getApproval(approvalId);
|
|
1081
|
+
}
|
|
1082
|
+
catch (err) {
|
|
1083
|
+
const status = err?.status;
|
|
1084
|
+
if (status === 404 || status === 403) {
|
|
1085
|
+
this.opts.log?.warn(`parall[${this.opts.accountId}]: approval ${approvalId} not accessible (${status}), acking stale dispatch`);
|
|
1086
|
+
return true;
|
|
1087
|
+
}
|
|
1088
|
+
this.opts.log?.warn(`parall[${this.opts.accountId}]: approval fetch failed for ${approvalId}, leaving pending: ${String(err)}`);
|
|
1089
|
+
return false;
|
|
1090
|
+
}
|
|
1091
|
+
if (!approval)
|
|
1092
|
+
return true;
|
|
1093
|
+
if (this.shuttingDown)
|
|
1094
|
+
return false;
|
|
1095
|
+
const dedupeKey = `approval:${approval.id}`;
|
|
1096
|
+
if (this.dispatchedTasks.has(dedupeKey))
|
|
1097
|
+
return false;
|
|
1098
|
+
this.dispatchedTasks.add(dedupeKey);
|
|
1099
|
+
this.opts.log?.info(`parall[${this.opts.accountId}]: approval decided: ${approval.id} (${approval.status})`);
|
|
1100
|
+
const statusLabel = approval.status === "approved" ? "Approved" : "Rejected";
|
|
1101
|
+
const execInfo = approval.execution_status ? ` | execution: ${approval.execution_status}` : "";
|
|
1102
|
+
const body = `${statusLabel}: ${approval.title}${execInfo}`;
|
|
1103
|
+
const event = {
|
|
1104
|
+
type: "approval",
|
|
1105
|
+
targetId: chatId ?? approval.chat_id,
|
|
1106
|
+
senderId: actorId ?? approval.decided_by ?? "system",
|
|
1107
|
+
senderName: "approver",
|
|
1108
|
+
messageId: approval.id,
|
|
1109
|
+
body,
|
|
1110
|
+
};
|
|
1111
|
+
let dispatched;
|
|
1112
|
+
try {
|
|
1113
|
+
dispatched = await this.handleInboundEvent(event);
|
|
1114
|
+
}
|
|
1115
|
+
catch (err) {
|
|
1116
|
+
this.dispatchedTasks.delete(dedupeKey);
|
|
1117
|
+
throw err;
|
|
1118
|
+
}
|
|
1119
|
+
if (!dispatched) {
|
|
1120
|
+
this.dispatchedTasks.delete(dedupeKey);
|
|
1121
|
+
}
|
|
1122
|
+
return dispatched;
|
|
1123
|
+
}
|
|
1062
1124
|
async catchUpFromDispatch(coldStart = false) {
|
|
1063
1125
|
const minAge = coldStart ? Date.now() - this.COLD_START_WINDOW_MS : 0;
|
|
1064
1126
|
let cursor;
|
|
@@ -1106,6 +1168,9 @@ export class ParallAgentGateway {
|
|
|
1106
1168
|
else if (item.event_type === "schedule.fire" && item.source_id) {
|
|
1107
1169
|
dispatched = await this.fetchAndHandleScheduleFire(item.source_id, item.actor_id);
|
|
1108
1170
|
}
|
|
1171
|
+
else if (item.event_type === "approval_decided" && item.source_id) {
|
|
1172
|
+
dispatched = await this.fetchAndHandleApprovalDecided(item.source_id, item.actor_id, item.chat_id ?? null);
|
|
1173
|
+
}
|
|
1109
1174
|
else if (item.event_type === "message" && item.source_id && item.chat_id) {
|
|
1110
1175
|
if (!this.tryClaimMessage(item.source_id))
|
|
1111
1176
|
continue;
|
package/dist/types.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export type DispatchState = {
|
|
|
20
20
|
};
|
|
21
21
|
/** Normalized inbound event from Parall. */
|
|
22
22
|
export type ParallEvent = {
|
|
23
|
-
type: "message" | "task" | "task_comment" | "schedule";
|
|
23
|
+
type: "message" | "task" | "task_comment" | "schedule" | "approval";
|
|
24
24
|
targetId: string;
|
|
25
25
|
targetName?: string;
|
|
26
26
|
targetType?: string;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,MAAM,MAAM,UAAU,GAAG;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACjE,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,2DAA2D;AAC3D,MAAM,MAAM,aAAa,GAAG;IAC1B,eAAe,EAAE,OAAO,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,kBAAkB,EAAE,UAAU,EAAE,CAAC;IACjC,UAAU,EAAE,WAAW,EAAE,CAAC;IAC1B,oFAAoF;IACpF,0BAA0B,CAAC,EAAE,MAAM,CAAC;CACrC,CAAC;AAEF,4CAA4C;AAC5C,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,SAAS,GAAG,MAAM,GAAG,cAAc,GAAG,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,MAAM,MAAM,UAAU,GAAG;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACjE,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,2DAA2D;AAC3D,MAAM,MAAM,aAAa,GAAG;IAC1B,eAAe,EAAE,OAAO,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,kBAAkB,EAAE,UAAU,EAAE,CAAC;IACjC,UAAU,EAAE,WAAW,EAAE,CAAC;IAC1B,oFAAoF;IACpF,0BAA0B,CAAC,EAAE,MAAM,CAAC;CACrC,CAAC;AAEF,4CAA4C;AAC5C,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,SAAS,GAAG,MAAM,GAAG,cAAc,GAAG,UAAU,GAAG,UAAU,CAAC;IACpE,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,KAAK,CAAC;QAClB,EAAE,EAAE,MAAM,CAAC;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;IACH,8DAA8D;IAC9D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,SAAS,GAAG,eAAe,GAAG,SAAS,GAAG,cAAc,CAAC;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parall/agent-core",
|
|
3
|
-
"version": "1.26.
|
|
3
|
+
"version": "1.26.2",
|
|
4
4
|
"description": "Shared agent runtime orchestration helpers for Parall",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"src"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@parall/sdk": "1.26.
|
|
29
|
+
"@parall/sdk": "1.26.2"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@types/node": "^22.0.0",
|
package/src/event-format.ts
CHANGED
|
@@ -35,6 +35,12 @@ export function buildEventBody(event: ParallEvent): string {
|
|
|
35
35
|
lines.push(`[From: ${event.senderName} (prll://${event.senderId})]`);
|
|
36
36
|
lines.push(`[Comment ID: prll://${event.messageId}]`);
|
|
37
37
|
lines.push("", event.body);
|
|
38
|
+
} else if (event.type === "approval") {
|
|
39
|
+
lines.push(`[Event: approval.decided]`);
|
|
40
|
+
lines.push(`[Approval: prll://${event.messageId}]`);
|
|
41
|
+
lines.push(`[Chat: prll://${event.targetId}]`);
|
|
42
|
+
lines.push(`[Decided by: ${event.senderName} (prll://${event.senderId})]`);
|
|
43
|
+
lines.push("", event.body);
|
|
38
44
|
} else if (event.type === "schedule") {
|
|
39
45
|
lines.push(`[Event: schedule.fired]`);
|
|
40
46
|
lines.push(`[Schedule: prll://${event.targetId}]`);
|
package/src/gateway-base.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { randomUUID } from "node:crypto";
|
|
|
5
5
|
import { MENTION_ALL_USER_ID, ParallClient, ParallWs } from "@parall/sdk";
|
|
6
6
|
import type {
|
|
7
7
|
AgentConfigUpdateData,
|
|
8
|
+
Approval,
|
|
8
9
|
Chat,
|
|
9
10
|
ChatUpdateData,
|
|
10
11
|
Comment,
|
|
@@ -294,6 +295,16 @@ export class ParallAgentGateway {
|
|
|
294
295
|
} catch (err) {
|
|
295
296
|
this.opts.log?.error(`parall[${this.opts.accountId}]: schedule fire dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
296
297
|
}
|
|
298
|
+
} else if (data.event_type === "approval_decided") {
|
|
299
|
+
if (!data.source_id) return;
|
|
300
|
+
try {
|
|
301
|
+
const dispatched = await this.fetchAndHandleApprovalDecided(data.source_id, data.actor_id, data.chat_id ?? null);
|
|
302
|
+
if (dispatched) {
|
|
303
|
+
this.opts.client.ackDispatchByID(this.opts.config.org_id, data.id).catch(() => {});
|
|
304
|
+
}
|
|
305
|
+
} catch (err) {
|
|
306
|
+
this.opts.log?.error(`parall[${this.opts.accountId}]: approval decided dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
307
|
+
}
|
|
297
308
|
} else if (data.event_type !== "message" && data.event_type !== "task_assign") {
|
|
298
309
|
// Truly unknown event_type — log so a newly-added dispatch type
|
|
299
310
|
// not yet wired here surfaces during runtime testing. "message"
|
|
@@ -365,7 +376,7 @@ export class ParallAgentGateway {
|
|
|
365
376
|
runtimeType: this.opts.runtimeType,
|
|
366
377
|
runtimeKey: this.opts.runtimeKey,
|
|
367
378
|
sessionId: this.activeSessionId,
|
|
368
|
-
chatId: event.type === "message" ? event.targetId : undefined,
|
|
379
|
+
chatId: (event.type === "message" || event.type === "approval") ? event.targetId : undefined,
|
|
369
380
|
triggerMessageId: event.messageId,
|
|
370
381
|
noReply: event.noReply ?? false,
|
|
371
382
|
contextFilePath: this.opts.contextFilePathForSession?.(sessionKey),
|
|
@@ -388,11 +399,13 @@ export class ParallAgentGateway {
|
|
|
388
399
|
event.type === "task" ? "task_assign" :
|
|
389
400
|
event.type === "task_comment" ? "task_comment" :
|
|
390
401
|
event.type === "schedule" ? "schedule_fire" :
|
|
402
|
+
event.type === "approval" ? "approval_decided" :
|
|
391
403
|
"mention",
|
|
392
404
|
trigger_ref:
|
|
393
405
|
event.type === "task" ? { task_id: event.targetId } :
|
|
394
406
|
event.type === "task_comment" ? { comment_id: event.messageId, task_id: event.targetId } :
|
|
395
407
|
event.type === "schedule" ? { schedule_id: event.targetId, run_id: event.messageId } :
|
|
408
|
+
event.type === "approval" ? { approval_id: event.messageId } :
|
|
396
409
|
{ message_id: event.messageId },
|
|
397
410
|
sender_id: event.senderId,
|
|
398
411
|
sender_name: event.senderName,
|
|
@@ -1197,6 +1210,53 @@ export class ParallAgentGateway {
|
|
|
1197
1210
|
return dispatched;
|
|
1198
1211
|
}
|
|
1199
1212
|
|
|
1213
|
+
private async fetchAndHandleApprovalDecided(approvalId: string, actorId: string | null, chatId: string | null): Promise<boolean> {
|
|
1214
|
+
let approval: Approval | null = null;
|
|
1215
|
+
try {
|
|
1216
|
+
approval = await this.opts.client.getApproval(approvalId);
|
|
1217
|
+
} catch (err: unknown) {
|
|
1218
|
+
const status = (err as { status?: number })?.status;
|
|
1219
|
+
if (status === 404 || status === 403) {
|
|
1220
|
+
this.opts.log?.warn(`parall[${this.opts.accountId}]: approval ${approvalId} not accessible (${status}), acking stale dispatch`);
|
|
1221
|
+
return true;
|
|
1222
|
+
}
|
|
1223
|
+
this.opts.log?.warn(`parall[${this.opts.accountId}]: approval fetch failed for ${approvalId}, leaving pending: ${String(err)}`);
|
|
1224
|
+
return false;
|
|
1225
|
+
}
|
|
1226
|
+
if (!approval) return true;
|
|
1227
|
+
|
|
1228
|
+
if (this.shuttingDown) return false;
|
|
1229
|
+
const dedupeKey = `approval:${approval.id}`;
|
|
1230
|
+
if (this.dispatchedTasks.has(dedupeKey)) return false;
|
|
1231
|
+
this.dispatchedTasks.add(dedupeKey);
|
|
1232
|
+
this.opts.log?.info(`parall[${this.opts.accountId}]: approval decided: ${approval.id} (${approval.status})`);
|
|
1233
|
+
|
|
1234
|
+
const statusLabel = approval.status === "approved" ? "Approved" : "Rejected";
|
|
1235
|
+
const execInfo = approval.execution_status ? ` | execution: ${approval.execution_status}` : "";
|
|
1236
|
+
const body = `${statusLabel}: ${approval.title}${execInfo}`;
|
|
1237
|
+
|
|
1238
|
+
const event: ParallEvent = {
|
|
1239
|
+
type: "approval",
|
|
1240
|
+
targetId: chatId ?? approval.chat_id,
|
|
1241
|
+
senderId: actorId ?? approval.decided_by ?? "system",
|
|
1242
|
+
senderName: "approver",
|
|
1243
|
+
messageId: approval.id,
|
|
1244
|
+
body,
|
|
1245
|
+
};
|
|
1246
|
+
|
|
1247
|
+
let dispatched: boolean;
|
|
1248
|
+
try {
|
|
1249
|
+
dispatched = await this.handleInboundEvent(event);
|
|
1250
|
+
} catch (err) {
|
|
1251
|
+
this.dispatchedTasks.delete(dedupeKey);
|
|
1252
|
+
throw err;
|
|
1253
|
+
}
|
|
1254
|
+
if (!dispatched) {
|
|
1255
|
+
this.dispatchedTasks.delete(dedupeKey);
|
|
1256
|
+
}
|
|
1257
|
+
return dispatched;
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1200
1260
|
private async catchUpFromDispatch(coldStart = false) {
|
|
1201
1261
|
const minAge = coldStart ? Date.now() - this.COLD_START_WINDOW_MS : 0;
|
|
1202
1262
|
let cursor: string | undefined;
|
|
@@ -1240,6 +1300,8 @@ export class ParallAgentGateway {
|
|
|
1240
1300
|
dispatched = await this.handleTaskComment(item.source_id, item.task_id, item.actor_id, item.delivery_reason);
|
|
1241
1301
|
} else if (item.event_type === "schedule.fire" && item.source_id) {
|
|
1242
1302
|
dispatched = await this.fetchAndHandleScheduleFire(item.source_id, item.actor_id);
|
|
1303
|
+
} else if (item.event_type === "approval_decided" && item.source_id) {
|
|
1304
|
+
dispatched = await this.fetchAndHandleApprovalDecided(item.source_id, item.actor_id, item.chat_id ?? null);
|
|
1243
1305
|
} else if (item.event_type === "message" && item.source_id && item.chat_id) {
|
|
1244
1306
|
if (!this.tryClaimMessage(item.source_id)) continue;
|
|
1245
1307
|
let msg: Awaited<ReturnType<typeof this.opts.client.getMessage>> | null = null;
|
package/src/types.ts
CHANGED
|
@@ -18,7 +18,7 @@ export type DispatchState = {
|
|
|
18
18
|
|
|
19
19
|
/** Normalized inbound event from Parall. */
|
|
20
20
|
export type ParallEvent = {
|
|
21
|
-
type: "message" | "task" | "task_comment" | "schedule";
|
|
21
|
+
type: "message" | "task" | "task_comment" | "schedule" | "approval";
|
|
22
22
|
targetId: string;
|
|
23
23
|
targetName?: string;
|
|
24
24
|
targetType?: string;
|