@parall/agent-core 1.26.1 → 1.26.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.
@@ -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,CAgDzD;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAK/D;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,CASnE"}
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"}
@@ -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}]`);
@@ -86,6 +86,7 @@ export declare class ParallAgentGateway {
86
86
  */
87
87
  private fetchAndHandleScheduleFire;
88
88
  private handleScheduleFire;
89
+ private fetchAndHandleApprovalDecided;
89
90
  private catchUpFromDispatch;
90
91
  private handleHello;
91
92
  private waitForDrain;
@@ -1 +1 @@
1
- {"version":3,"file":"gateway-base.d.ts","sourceRoot":"","sources":["../src/gateway-base.ts"],"names":[],"mappings":"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"}
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,EAatB,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAEV,eAAe,EAGf,aAAa,EAEd,MAAM,uBAAuB,CAAC;AAoD/B,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,YAAY,CAAC;IACrB,EAAE,EAAE,QAAQ,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE;QACN,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,eAAe,EAAE,eAAe,CAAC;IACjC,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAI3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,yBAAyB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACvE,0FAA0F;IAC1F,wBAAwB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACtE,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,qBAAqB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACvE,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,eAAe,CAAC,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,QAAQ,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACjH,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACjD,CAAC;AAUF,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAKnF;AAqCD,qBAAa,kBAAkB;IAmCjB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAlCjC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA+B;IAC3D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqC;IACtE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqB;IACrD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqB;IACxD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAsC;IACjE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAK5B;IAEF,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,cAAc,CAA+C;IACrE,OAAO,CAAC,kBAAkB,CAAS;IACnC,OAAO,CAAC,eAAe,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAS;IAMzB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,kBAAkB,CAAK;IAC/B,OAAO,CAAC,cAAc,CAAyB;IAE/C,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAQ;IAChD,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAS;IAI9C,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAS;gBAEjB,IAAI,EAAE,oBAAoB;IAKjD,GAAG,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAmIlD,OAAO,CAAC,eAAe;IAavB,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,oBAAoB;YAoBd,eAAe;YA+Bf,iBAAiB;IA0F/B,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,uBAAuB;IAW/B,kEAAkE;IAClE,OAAO,CAAC,eAAe;IASvB,kEAAkE;IAClE,OAAO,CAAC,eAAe;YAQT,gCAAgC;YAUhC,WAAW;YAiGX,gBAAgB;YAkFhB,eAAe;YAgFf,kBAAkB;YAqFlB,kBAAkB;YAkBlB,4BAA4B;YAoD5B,aAAa;YA+Bb,oBAAoB;YAoCpB,kBAAkB;YAwBlB,iBAAiB;IAiF/B;;;;;;;OAOG;YACW,0BAA0B;YAsB1B,kBAAkB;YAsClB,6BAA6B;YA+C7B,mBAAmB;YAoGnB,WAAW;IA6DzB,OAAO,CAAC,YAAY;YAiBN,QAAQ;CA4CvB"}
@@ -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
- "mention",
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
- { message_id: event.messageId },
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;
@@ -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;IACvD,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"}
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.1",
3
+ "version": "1.26.3",
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.1"
29
+ "@parall/sdk": "1.26.3"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@types/node": "^22.0.0",
@@ -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}]`);
@@ -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;