@parall/agent-core 1.23.0 → 1.25.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.
@@ -7,7 +7,7 @@
7
7
  * `@parall/agent-core` stays runtime-neutral and exports only text + pure
8
8
  * helpers here.
9
9
  */
10
- export declare const BRIDGE_WORKSPACE_INSTRUCTIONS = "# Agent workspace\n\nYou are an agent in Parall IM. You participate in chats, handle tasks, and interact exclusively through the Parall CLI.\n\n## Message Model\n\nIncoming events are rendered as structured `[Event: ...]` blocks.\nEach event includes `[Chat: ... (prll://cht_xxx)]` \u2014 use that chat ID (or full URI) when replying.\n\n**Your plain-text output is not delivered to anyone** \u2014 it is recorded as suppressed thinking in your session steps and discarded from the chat.\nTo say something in a chat, you **must** invoke the Parall CLI via your shell/exec tool. To stay silent, simply do not invoke it.\n\n## Parall CLI\n\nAll outbound interactions go through `@parall/cli`. Credentials are pre-injected as environment variables \u2014 no setup needed.\n\n- `npx --yes @parall/cli@latest messages send prll://cht_xxx --text \"...\"` \u2014 reply into the triggering chat\n- `npx --yes @parall/cli@latest dm prll://usr_xxx --text \"...\" [--no-reply]` \u2014 direct message another user\n- `npx --yes @parall/cli@latest tasks update prll://tsk_xxx --status in_progress` \u2014 task state\n- `npx --yes @parall/cli@latest no-reply [--reason \"...\"]` \u2014 explicitly declare this turn silent (audit signal; not required for silence, just clarifies intent)\n\nThe bridge injects Parall context via environment variables. The static credentials `PRLL_API_URL`, `PRLL_API_KEY`, and `PRLL_ORG_ID` are always set. Per-dispatch context \u2014 `PRLL_SESSION_ID`, `PRLL_CHAT_ID`, `PRLL_TRIGGER_MESSAGE_ID`, `PRLL_STEP_ID_FILE` \u2014 is set in subprocess-per-dispatch runtimes (Claude Code); in long-running runtimes (Codex) those may be absent and the CLI will fall back to whatever defaults you supply on the command line.\n\n## Guardrails\n\n- A dispatch may coalesce multiple events. Decide per event whether to reply via `messages send` / `dm` \u2014 events you do not act on simply receive no reply.\n- If an event carries `[Hint: no_reply]`, do not send anything for that event. `no-reply` is optional and only useful as an explicit intent marker.\n- Never try to \"speak\" by typing sentences like \"No response needed\" / \"Noted\" / \"OK\" \u2014 they are discarded, so they accomplish nothing except polluting your session log.\n- Keep CLI replies concise and task-focused.\n\nSee `docs/engineering-design/agent-dm-loop-prevention.md` \u00A7 Layer 0 for why plain text is never auto-projected.\n";
10
+ export declare const BRIDGE_WORKSPACE_INSTRUCTIONS = "# Agent workspace\n\nYou are an agent in Parall IM. You participate in chats, handle tasks, and interact exclusively through the Parall CLI.\n\n## Message Model\n\nIncoming events are rendered as structured `[Event: ...]` blocks.\nEach event includes `[Chat: ... (prll://cht_xxx)]` \u2014 use that chat ID (or full URI) when replying.\n\n**Your plain-text output is not delivered to anyone** \u2014 it is recorded as suppressed thinking in your session steps and discarded from the chat.\nTo say something in a chat, you **must** invoke the Parall CLI via your shell/exec tool. To stay silent, simply do not invoke it.\n\n## Parall CLI\n\nAll outbound interactions go through the `parall` CLI. Credentials are pre-injected as environment variables \u2014 no setup needed. If `parall` is not on PATH, use `npx --yes @parall/cli@latest` instead.\n\n- `parall messages send prll://cht_xxx --text \"...\"` \u2014 reply into the triggering chat\n- `parall dm prll://usr_xxx --text \"...\" [--no-reply]` \u2014 direct message another user\n- `parall tasks update prll://tsk_xxx --status in_progress` \u2014 task state\n- `parall no-reply [--reason \"...\"]` \u2014 explicitly declare this turn silent (audit signal; not required for silence, just clarifies intent)\n\nThe bridge injects Parall context via environment variables. The static credentials `PRLL_API_URL`, `PRLL_API_KEY`, and `PRLL_ORG_ID` are always set. Per-dispatch context \u2014 `PRLL_SESSION_ID`, `PRLL_CHAT_ID`, `PRLL_TRIGGER_MESSAGE_ID`, `PRLL_STEP_ID_FILE` \u2014 is set in subprocess-per-dispatch runtimes (Claude Code); in long-running runtimes (Codex) those may be absent and the CLI will fall back to whatever defaults you supply on the command line.\n\n## Attachments\n\nImage attachments are pre-downloaded under `.parall/attachments/<messageId>/`. Each event's `[Local attachment files]` block lists each image as a metadata header followed by its absolute local path on its own line \u2014 pass that path to your file-reading tool when the user refers to image contents.\n\nSupported image types: PNG, JPEG, WebP, GIF. Other attachment types (PDFs, archives, etc.) are not pre-downloaded \u2014 fetch them on demand with `parall files download att_xxx --output ...`.\n\n## Guardrails\n\n- A dispatch may coalesce multiple events. Decide per event whether to reply via `messages send` / `dm` \u2014 events you do not act on simply receive no reply.\n- If an event carries `[Hint: no_reply]`, do not send anything for that event. `no-reply` is optional and only useful as an explicit intent marker.\n- Never try to \"speak\" by typing sentences like \"No response needed\" / \"Noted\" / \"OK\" \u2014 they are discarded, so they accomplish nothing except polluting your session log.\n- Keep CLI replies concise and task-focused.\n\nSee `docs/engineering-design/agent-dm-loop-prevention.md` \u00A7 Layer 0 for why plain text is never auto-projected.\n\n## Approval Flow\n\nWhen you try an action (e.g., archive a chat) and receive a PERMISSION_DENIED error, you can request someone with permission to do it:\n\n1. The error includes a `PERMISSION_DENIED` code. For commonly approvable actions (archive, delete, restore), a `Tip:` line with an approval-request template is printed \u2014 copy it and fill in the remaining placeholders (`--chat`, `--title`, `--reason`)\n2. Request approval: `parall approvals request --action chat.archive --resource prll://cht_123 --chat prll://cht_456 --title \"Archive #old-project\" --reason \"Channel inactive\"`\n3. A card will appear in the specified chat for someone with permission to approve\n4. Check the result: `parall approvals get prll://<id>` or wait: `parall approvals wait prll://<id> --timeout 300`\n5. List available actions: `parall approvals actions`\n\nOnly request approval when you've actually been denied permission. Don't request approval preemptively.\n";
11
11
  /** Extracts the `command` string from a shell/bash tool call's input payload. */
12
12
  export declare function extractShellCommand(input: unknown): string | undefined;
13
13
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"bridge-workspace.d.ts","sourceRoot":"","sources":["../src/bridge-workspace.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,6BAA6B,m3EA+BzC,CAAC;AAEF,iFAAiF;AACjF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAItE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,CAmBzE;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAKxE;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAI3E"}
1
+ {"version":3,"file":"bridge-workspace.d.ts","sourceRoot":"","sources":["../src/bridge-workspace.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,6BAA6B,gzHAiDzC,CAAC;AAEF,iFAAiF;AACjF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAItE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,CAmBzE;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAKxE;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAI3E"}
@@ -21,15 +21,21 @@ To say something in a chat, you **must** invoke the Parall CLI via your shell/ex
21
21
 
22
22
  ## Parall CLI
23
23
 
24
- All outbound interactions go through \`@parall/cli\`. Credentials are pre-injected as environment variables — no setup needed.
24
+ All outbound interactions go through the \`parall\` CLI. Credentials are pre-injected as environment variables — no setup needed. If \`parall\` is not on PATH, use \`npx --yes @parall/cli@latest\` instead.
25
25
 
26
- - \`npx --yes @parall/cli@latest messages send prll://cht_xxx --text "..."\` — reply into the triggering chat
27
- - \`npx --yes @parall/cli@latest dm prll://usr_xxx --text "..." [--no-reply]\` — direct message another user
28
- - \`npx --yes @parall/cli@latest tasks update prll://tsk_xxx --status in_progress\` — task state
29
- - \`npx --yes @parall/cli@latest no-reply [--reason "..."]\` — explicitly declare this turn silent (audit signal; not required for silence, just clarifies intent)
26
+ - \`parall messages send prll://cht_xxx --text "..."\` — reply into the triggering chat
27
+ - \`parall dm prll://usr_xxx --text "..." [--no-reply]\` — direct message another user
28
+ - \`parall tasks update prll://tsk_xxx --status in_progress\` — task state
29
+ - \`parall no-reply [--reason "..."]\` — explicitly declare this turn silent (audit signal; not required for silence, just clarifies intent)
30
30
 
31
31
  The bridge injects Parall context via environment variables. The static credentials \`PRLL_API_URL\`, \`PRLL_API_KEY\`, and \`PRLL_ORG_ID\` are always set. Per-dispatch context — \`PRLL_SESSION_ID\`, \`PRLL_CHAT_ID\`, \`PRLL_TRIGGER_MESSAGE_ID\`, \`PRLL_STEP_ID_FILE\` — is set in subprocess-per-dispatch runtimes (Claude Code); in long-running runtimes (Codex) those may be absent and the CLI will fall back to whatever defaults you supply on the command line.
32
32
 
33
+ ## Attachments
34
+
35
+ Image attachments are pre-downloaded under \`.parall/attachments/<messageId>/\`. Each event's \`[Local attachment files]\` block lists each image as a metadata header followed by its absolute local path on its own line — pass that path to your file-reading tool when the user refers to image contents.
36
+
37
+ Supported image types: PNG, JPEG, WebP, GIF. Other attachment types (PDFs, archives, etc.) are not pre-downloaded — fetch them on demand with \`parall files download att_xxx --output ...\`.
38
+
33
39
  ## Guardrails
34
40
 
35
41
  - A dispatch may coalesce multiple events. Decide per event whether to reply via \`messages send\` / \`dm\` — events you do not act on simply receive no reply.
@@ -38,6 +44,18 @@ The bridge injects Parall context via environment variables. The static credenti
38
44
  - Keep CLI replies concise and task-focused.
39
45
 
40
46
  See \`docs/engineering-design/agent-dm-loop-prevention.md\` § Layer 0 for why plain text is never auto-projected.
47
+
48
+ ## Approval Flow
49
+
50
+ When you try an action (e.g., archive a chat) and receive a PERMISSION_DENIED error, you can request someone with permission to do it:
51
+
52
+ 1. The error includes a \`PERMISSION_DENIED\` code. For commonly approvable actions (archive, delete, restore), a \`Tip:\` line with an approval-request template is printed — copy it and fill in the remaining placeholders (\`--chat\`, \`--title\`, \`--reason\`)
53
+ 2. Request approval: \`parall approvals request --action chat.archive --resource prll://cht_123 --chat prll://cht_456 --title "Archive #old-project" --reason "Channel inactive"\`
54
+ 3. A card will appear in the specified chat for someone with permission to approve
55
+ 4. Check the result: \`parall approvals get prll://<id>\` or wait: \`parall approvals wait prll://<id> --timeout 300\`
56
+ 5. List available actions: \`parall approvals actions\`
57
+
58
+ Only request approval when you've actually been denied permission. Don't request approval preemptively.
41
59
  `;
42
60
  /** Extracts the `command` string from a shell/bash tool call's input payload. */
43
61
  export function extractShellCommand(input) {
@@ -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,CA+CzD;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,CAgDzD;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,CASnE"}
@@ -31,6 +31,8 @@ export function buildEventBody(event) {
31
31
  ? `${event.targetName} (prll://${event.targetId})`
32
32
  : `prll://${event.targetId}`;
33
33
  lines.push(`[Task: ${taskLabel}]`);
34
+ if (event.deliveryReason)
35
+ lines.push(`[Delivery: ${sanitizeMeta(event.deliveryReason)}]`);
34
36
  lines.push(`[From: ${event.senderName} (prll://${event.senderId})]`);
35
37
  lines.push(`[Comment ID: prll://${event.messageId}]`);
36
38
  lines.push("", event.body);
@@ -68,6 +68,7 @@ export declare class ParallAgentGateway {
68
68
  private buildMessageDispatchDecision;
69
69
  private handleMessage;
70
70
  private handleTaskAssignment;
71
+ private handleTaskDispatch;
71
72
  private handleTaskComment;
72
73
  /**
73
74
  * Fetch the schedule_run snapshot, then feed it as an inbound event. 404 is
@@ -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,EAYtB,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,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;IAyHlD,OAAO,CAAC,eAAe;IAavB,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,oBAAoB;YAmBd,eAAe;YA6Bf,iBAAiB;IAsF/B,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,eAAe;YAQT,gCAAgC;YAUhC,WAAW;YAoFX,gBAAgB;YAkFhB,eAAe;YA6Ef,kBAAkB;YA2ElB,kBAAkB;YAkBlB,4BAA4B;YAoD5B,aAAa;YA+Bb,oBAAoB;YAoCpB,kBAAkB;YAwBlB,iBAAiB;IAiF/B;;;;;;;OAOG;YACW,0BAA0B;YAsB1B,kBAAkB;YAsClB,mBAAmB;YAkGnB,WAAW;IA6DzB,OAAO,CAAC,YAAY;YAiBN,QAAQ;CA4CvB"}
@@ -157,7 +157,7 @@ export class ParallAgentGateway {
157
157
  if (!data.source_id || !data.task_id)
158
158
  return;
159
159
  try {
160
- const dispatched = await this.handleTaskComment(data.source_id, data.task_id, data.actor_id);
160
+ const dispatched = await this.handleTaskComment(data.source_id, data.task_id, data.actor_id, data.delivery_reason);
161
161
  if (dispatched) {
162
162
  this.opts.client.ackDispatchByID(this.opts.config.org_id, data.id).catch(() => { });
163
163
  }
@@ -166,6 +166,19 @@ export class ParallAgentGateway {
166
166
  this.opts.log?.error(`parall[${this.opts.accountId}]: task comment dispatch failed for ${data.source_id}: ${String(err)}`);
167
167
  }
168
168
  }
169
+ else if (data.event_type === "task_update") {
170
+ if (!data.task_id)
171
+ return;
172
+ try {
173
+ const dispatched = await this.handleTaskDispatch(data.task_id, data.source_id ?? data.task_id, { allowCreator: true });
174
+ if (dispatched) {
175
+ this.opts.client.ackDispatchByID(this.opts.config.org_id, data.id).catch(() => { });
176
+ }
177
+ }
178
+ catch (err) {
179
+ this.opts.log?.error(`parall[${this.opts.accountId}]: task update dispatch failed for ${data.task_id}: ${String(err)}`);
180
+ }
181
+ }
169
182
  else if (data.event_type === "schedule.fire") {
170
183
  if (!data.source_id)
171
184
  return;
@@ -828,7 +841,26 @@ export class ParallAgentGateway {
828
841
  }
829
842
  return dispatched;
830
843
  }
831
- async handleTaskComment(commentId, taskId, actorId) {
844
+ async handleTaskDispatch(taskId, ackSourceId, opts = {}) {
845
+ let task = null;
846
+ try {
847
+ task = await this.opts.client.getTask(this.opts.config.org_id, taskId);
848
+ }
849
+ catch (err) {
850
+ const status = err?.status;
851
+ if (status === 404)
852
+ return true;
853
+ throw err;
854
+ }
855
+ const isAssignee = task.assignee_id === this.opts.agentUserId;
856
+ const isCreatorUpdate = opts.allowCreator === true && task.creator_id === this.opts.agentUserId;
857
+ if (!isAssignee && !isCreatorUpdate) {
858
+ this.opts.log?.info(`parall[${this.opts.accountId}]: skipping stale task dispatch ${ackSourceId ?? taskId} — assigned to ${task.assignee_id}, creator ${task.creator_id}`);
859
+ return true;
860
+ }
861
+ return this.handleTaskAssignment(task, ackSourceId);
862
+ }
863
+ async handleTaskComment(commentId, taskId, actorId, deliveryReason) {
832
864
  if (this.shuttingDown)
833
865
  return false; // drain window — let server requeue via catch-up
834
866
  const dedupeKey = `comment:${commentId}`;
@@ -885,6 +917,7 @@ export class ParallAgentGateway {
885
917
  senderName: comment.author?.display_name ?? actorId ?? "unknown",
886
918
  messageId: commentId,
887
919
  body: parts.join("\n"),
920
+ deliveryReason: deliveryReason ?? undefined,
888
921
  ackSourceType: "comment",
889
922
  ackSourceId: commentId,
890
923
  };
@@ -995,37 +1028,25 @@ export class ParallAgentGateway {
995
1028
  try {
996
1029
  let dispatched = false;
997
1030
  if (item.event_type === "task_assign" && item.task_id) {
998
- let task = null;
999
- let taskFetchFailed = false;
1000
1031
  try {
1001
- task = await this.opts.client.getTask(this.opts.config.org_id, item.task_id);
1032
+ dispatched = await this.handleTaskDispatch(item.task_id, item.source_id ?? item.task_id);
1002
1033
  }
1003
1034
  catch (err) {
1004
- const status = err?.status;
1005
- if (status === 404) {
1006
- task = null;
1007
- }
1008
- else {
1009
- taskFetchFailed = true;
1010
- this.opts.log?.warn(`parall[${this.opts.accountId}]: catch-up task fetch failed for ${item.task_id}, leaving pending: ${String(err)}`);
1011
- }
1012
- }
1013
- if (taskFetchFailed)
1035
+ this.opts.log?.warn(`parall[${this.opts.accountId}]: catch-up task fetch failed for ${item.task_id}, leaving pending: ${String(err)}`);
1014
1036
  continue;
1015
- if (task) {
1016
- if (task.assignee_id !== this.opts.agentUserId) {
1017
- this.opts.log?.info(`parall[${this.opts.accountId}]: skipping stale task dispatch ${item.id} — reassigned to ${task.assignee_id}`);
1018
- this.opts.client.ackDispatchByID(this.opts.config.org_id, item.id).catch(() => { });
1019
- continue;
1020
- }
1021
- dispatched = await this.handleTaskAssignment(task);
1022
1037
  }
1023
- else {
1024
- dispatched = true;
1038
+ }
1039
+ else if (item.event_type === "task_update" && item.task_id) {
1040
+ try {
1041
+ dispatched = await this.handleTaskDispatch(item.task_id, item.source_id ?? item.task_id, { allowCreator: true });
1042
+ }
1043
+ catch (err) {
1044
+ this.opts.log?.warn(`parall[${this.opts.accountId}]: catch-up task fetch failed for ${item.task_id}, leaving pending: ${String(err)}`);
1045
+ continue;
1025
1046
  }
1026
1047
  }
1027
1048
  else if (item.event_type === "task_comment" && item.source_id && item.task_id) {
1028
- dispatched = await this.handleTaskComment(item.source_id, item.task_id, item.actor_id);
1049
+ dispatched = await this.handleTaskComment(item.source_id, item.task_id, item.actor_id, item.delivery_reason);
1029
1050
  }
1030
1051
  else if (item.event_type === "schedule.fire" && item.source_id) {
1031
1052
  dispatched = await this.fetchAndHandleScheduleFire(item.source_id, item.actor_id);
@@ -0,0 +1,53 @@
1
+ import type { DispatchContext, GatewayLogger } from "../dispatch-adapter.js";
2
+ import type { LocalAttachmentResult, PreparedLocalImage } from "../prompt-fragments.js";
3
+ import type { ParallEvent } from "../types.js";
4
+ export type { LocalAttachmentResult, PreparedLocalImage };
5
+ export type LocalAttachmentOptions = {
6
+ workspaceDir: string;
7
+ maxTotalImageBytes?: number;
8
+ maxCacheBytes?: number;
9
+ downloadTimeoutMs?: number;
10
+ attachmentTtlMs?: number;
11
+ /**
12
+ * Cooldown window for background cache maintenance (TTL cleanup + LRU prune).
13
+ * When >0 (default), only one maintenance pass per cooldown interval runs per
14
+ * root, in the background, and dispatch never waits on it. When 0, the pass
15
+ * runs synchronously in-line — used by tests that need deterministic prune
16
+ * timing.
17
+ */
18
+ maintenanceCooldownMs?: number;
19
+ log?: GatewayLogger;
20
+ };
21
+ /**
22
+ * Per-dispatch cap on image bytes a runtime turn receives. Counts declared
23
+ * attachment sizes plus fresh download bytes; cache hits are NOT recharged
24
+ * against this budget — those are already on disk and bounded separately by
25
+ * `DEFAULT_ATTACHMENT_CACHE_MAX_BYTES` below. The cap exists to keep any one
26
+ * dispatch from saturating the bridge↔runtime hop with a single oversized
27
+ * batch; the cache cap exists to keep the workspace from growing unbounded.
28
+ */
29
+ export declare const DEFAULT_MAX_TOTAL_IMAGE_BYTES: number;
30
+ /**
31
+ * Workspace cache ceiling. The default is generous for typical operator setups,
32
+ * but on small PVCs (e.g. 1 GiB) it can claim a meaningful fraction of disk.
33
+ * Operators on constrained storage should override via `LocalAttachmentOptions.maxCacheBytes`.
34
+ */
35
+ export declare const DEFAULT_ATTACHMENT_CACHE_MAX_BYTES: number;
36
+ export declare const DEFAULT_ATTACHMENT_DOWNLOAD_TIMEOUT_MS = 30000;
37
+ export declare const DEFAULT_ATTACHMENT_TTL_MS: number;
38
+ export declare const DEFAULT_MAINTENANCE_COOLDOWN_MS: number;
39
+ export declare function prepareLocalImageAttachments(event: ParallEvent, context: DispatchContext, opts: LocalAttachmentOptions): Promise<LocalAttachmentResult>;
40
+ export declare function appendLocalAttachmentRefs(body: string, result: LocalAttachmentResult): string;
41
+ export declare function appendPreparedLocalAttachmentRefs(body: string, event: ParallEvent, context: DispatchContext, opts: LocalAttachmentOptions): Promise<{
42
+ body: string;
43
+ attachments: LocalAttachmentResult;
44
+ }>;
45
+ export declare function pinLocalAttachmentPaths(images: PreparedLocalImage[]): () => void;
46
+ /**
47
+ * Append `.parall/` to the workspace's git info/exclude. Best-effort — a
48
+ * missing exclude entry should not block dispatch. Used by both Claude and
49
+ * Codex bridges' workspace bootstrap; lives here next to the attachment
50
+ * download logic so the directory convention stays in one place.
51
+ */
52
+ export declare function ensureLocalAttachmentGitExclude(workingDirectory: string): void;
53
+ //# sourceMappingURL=attachment-input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachment-input.d.ts","sourceRoot":"","sources":["../../src/internal/attachment-input.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE7E,OAAO,KAAK,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACxF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAK/C,YAAY,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,CAAC;AAE1D,MAAM,MAAM,sBAAsB,GAAG;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,GAAG,CAAC,EAAE,aAAa,CAAC;CACrB,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,6BAA6B,QAAmB,CAAC;AAC9D;;;;GAIG;AACH,eAAO,MAAM,kCAAkC,QAAoB,CAAC;AACpE,eAAO,MAAM,sCAAsC,QAAS,CAAC;AAC7D,eAAO,MAAM,yBAAyB,QAAsB,CAAC;AAC7D,eAAO,MAAM,+BAA+B,QAAY,CAAC;AAmBzD,wBAAsB,4BAA4B,CAChD,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,sBAAsB,GAC3B,OAAO,CAAC,qBAAqB,CAAC,CA2HhC;AAED,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,qBAAqB,GAC5B,MAAM,CAGR;AAED,wBAAsB,iCAAiC,CACrD,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,sBAAsB,GAC3B,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,qBAAqB,CAAA;CAAE,CAAC,CAG/D;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,kBAAkB,EAAE,GAAG,MAAM,IAAI,CAchF;AAMD;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAgB9E"}