@parall/agent-core 1.29.0 → 1.29.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.
@@ -80,19 +80,20 @@ export interface DispatchAdapter {
80
80
  /** Dispatch a Parall event to the runtime and emit normalized runtime events. */
81
81
  dispatch(opts: DispatchOpts): AsyncIterable<RuntimeEvent>;
82
82
  /**
83
- * Inject a user message into the running subprocess's stdin mid-turn so the
84
- * runtime reads it between tool calls and steers immediately, rather than
85
- * waiting for the current turn to complete.
83
+ * Inject a user message into the running runtime mid-turn so it steers
84
+ * immediately, rather than waiting for the current turn to complete.
86
85
  *
87
- * Returns true if the message was successfully written to stdin; false if no
88
- * live process exists for the session (caller should fall back to mainBuffer).
86
+ * Returns true if the injection succeeded; false if no live process/session
87
+ * exists (caller falls back to mainBuffer next-turn path). May return a
88
+ * Promise when the injection requires an async round-trip (e.g. Codex
89
+ * turn/steer JSON-RPC) — the gateway awaits it.
89
90
  *
90
91
  * The gateway still pushes the event to mainBuffer after a successful
91
92
  * injection — drainMainBuffer will call dispatch() for it, and dispatch()
92
- * must detect the pending injection (skip the stdin write) and only consume
93
- * the parser output that Claude produced in response.
93
+ * must detect the pending injection (skip the duplicate input) and only
94
+ * consume output produced in response.
94
95
  */
95
- enqueueDuringDispatch?(sessionKey: string, body: string): boolean;
96
+ enqueueDuringDispatch?(sessionKey: string, body: string): boolean | Promise<boolean>;
96
97
  /** True if enqueueDuringDispatch was called and the injections have not yet been consumed by dispatch(). */
97
98
  hasPendingInjections?(sessionKey: string): boolean;
98
99
  /** Fork the current runtime session for concurrent handling. Return null to buffer on main. */
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch-adapter.d.ts","sourceRoot":"","sources":["../src/dispatch-adapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dispatch-adapter.d.ts","sourceRoot":"","sources":["../src/dispatch-adapter.ts"],"names":[],"mappings":"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"}
@@ -41,6 +41,7 @@ export declare class ParallAgentGateway {
41
41
  private readonly opts;
42
42
  private readonly chatInfoMap;
43
43
  private readonly activeDispatches;
44
+ private readonly injectedTypingCounts;
44
45
  private readonly dispatchedTasks;
45
46
  private readonly dispatchedMessages;
46
47
  private readonly forkStates;
@@ -63,6 +64,10 @@ export declare class ParallAgentGateway {
63
64
  private tryClaimMessage;
64
65
  private startTyping;
65
66
  private stopTyping;
67
+ private shouldShowTyping;
68
+ private startInjectedTyping;
69
+ private takeInjectedTypingCount;
70
+ private runDispatchWithTyping;
66
71
  private buildDispatchContext;
67
72
  private createInputStep;
68
73
  private createRuntimeStep;
@@ -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":"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"}
@@ -54,6 +54,7 @@ export class ParallAgentGateway {
54
54
  opts;
55
55
  chatInfoMap = new Map();
56
56
  activeDispatches = new Map();
57
+ injectedTypingCounts = new Map();
57
58
  dispatchedTasks = new Set();
58
59
  dispatchedMessages = new Set();
59
60
  forkStates = new Map();
@@ -265,6 +266,35 @@ export class ParallAgentGateway {
265
266
  if (this.opts.ws.state === "connected")
266
267
  this.opts.ws.sendTyping(chatId, "stop");
267
268
  }
269
+ shouldShowTyping(event) {
270
+ return event.type === "message" && event.targetId.startsWith("cht_") && !event.noReply;
271
+ }
272
+ startInjectedTyping(event) {
273
+ if (!this.shouldShowTyping(event))
274
+ return;
275
+ this.startTyping(event.targetId);
276
+ this.injectedTypingCounts.set(event.targetId, (this.injectedTypingCounts.get(event.targetId) ?? 0) + 1);
277
+ }
278
+ takeInjectedTypingCount(chatId) {
279
+ const count = this.injectedTypingCounts.get(chatId) ?? 0;
280
+ this.injectedTypingCounts.delete(chatId);
281
+ return count;
282
+ }
283
+ async runDispatchWithTyping(event, sessionKey, bodyForAgent, earlierEvents = [], captureText, opts = {}) {
284
+ const showTyping = !opts.suppressStart && (this.shouldShowTyping(event) || earlierEvents.some(e => this.shouldShowTyping(e)));
285
+ if (showTyping)
286
+ this.startTyping(event.targetId);
287
+ try {
288
+ return await this.runDispatch(event, sessionKey, bodyForAgent, earlierEvents, captureText);
289
+ }
290
+ finally {
291
+ if (showTyping)
292
+ this.stopTyping(event.targetId);
293
+ for (let i = 0; i < (opts.injectedTypingCount ?? 0); i++) {
294
+ this.stopTyping(event.targetId);
295
+ }
296
+ }
297
+ }
268
298
  buildDispatchContext(event, sessionKey) {
269
299
  const binding = this.sessionBindings.get(sessionKey);
270
300
  return {
@@ -306,6 +336,7 @@ export class ParallAgentGateway {
306
336
  sender_id: event.senderId,
307
337
  sender_name: event.senderName,
308
338
  summary: event.body.substring(0, 200),
339
+ ...(event.sentAt ? { sent_at: event.sentAt } : {}),
309
340
  },
310
341
  });
311
342
  }
@@ -637,7 +668,7 @@ export class ParallAgentGateway {
637
668
  const earlier = events.slice(0, -1);
638
669
  try {
639
670
  const batchText = [];
640
- const dispatched = await this.runDispatch(last, fork.fork.sessionKey, buildForkScopePrefix(last) + buildEventBody(last), earlier, batchText);
671
+ const dispatched = await this.runDispatchWithTyping(last, fork.fork.sessionKey, buildForkScopePrefix(last) + buildEventBody(last), earlier, batchText);
641
672
  if (!dispatched) {
642
673
  // Shutdown short-circuit — resolve un-acked so the server requeues
643
674
  // for the replacement pod and stop draining further items.
@@ -740,13 +771,14 @@ export class ParallAgentGateway {
740
771
  }
741
772
  const event = events[events.length - 1];
742
773
  const earlier = events.slice(0, -1);
743
- const skipForkSplice = this.opts.dispatchAdapter.hasPendingInjections?.(this.opts.runtimeKey) ?? false;
744
- const pendingFork = skipForkSplice ? [] : this.dispatchState.pendingForkResults.splice(0);
774
+ const hasPendingInjections = this.opts.dispatchAdapter.hasPendingInjections?.(this.opts.runtimeKey) ?? false;
775
+ const injectedTypingCount = hasPendingInjections ? this.takeInjectedTypingCount(event.targetId) : 0;
776
+ const pendingFork = hasPendingInjections ? [] : this.dispatchState.pendingForkResults.splice(0);
745
777
  const forkPrefix = buildForkResultPrefix(pendingFork);
746
778
  this.dispatchState.mainCurrentTargetId = event.targetId;
747
779
  this.dispatchState.mainPreDispatchBranchPoint =
748
780
  this.opts.dispatchAdapter.getBranchPoint?.(this.opts.runtimeKey);
749
- const dispatched = await this.runDispatch(event, this.opts.runtimeKey, forkPrefix + buildEventBody(event), earlier);
781
+ const dispatched = await this.runDispatchWithTyping(event, this.opts.runtimeKey, forkPrefix + buildEventBody(event), earlier, undefined, { suppressStart: injectedTypingCount > 0, injectedTypingCount });
750
782
  if (!dispatched) {
751
783
  // Shutdown: skip the ack so the server redelivers these buffered
752
784
  // events to the replacement pod via dispatch catch-up. Put both the
@@ -787,7 +819,7 @@ export class ParallAgentGateway {
787
819
  this.opts.dispatchAdapter.getBranchPoint?.(this.opts.runtimeKey);
788
820
  let dispatched = false;
789
821
  try {
790
- dispatched = await this.runDispatch(event, this.opts.runtimeKey, forkPrefix + buildEventBody(event));
822
+ dispatched = await this.runDispatchWithTyping(event, this.opts.runtimeKey, forkPrefix + buildEventBody(event));
791
823
  if (!dispatched) {
792
824
  // Shutdown short-circuit — restore the fork results so a future
793
825
  // pod can replay them, and return false so handleMessage skips ack.
@@ -803,11 +835,22 @@ export class ParallAgentGateway {
803
835
  if (this.shuttingDown) {
804
836
  return false;
805
837
  }
838
+ // Push synchronously BEFORE the (possibly async) steer attempt so
839
+ // arrival order is preserved and the event cannot be orphaned in a
840
+ // gap between the steer await and the push.
841
+ this.dispatchState.mainBuffer.push(event);
806
842
  if (this.dispatchState.mainCurrentTargetId === event.targetId &&
807
- this.opts.dispatchAdapter.enqueueDuringDispatch?.(this.opts.runtimeKey, buildEventBody(event))) {
808
- this.opts.log?.info(`parall[${this.opts.accountId}]: steer injected to stdin for ${event.messageId} (will drain for bookkeeping)`);
843
+ await this.opts.dispatchAdapter.enqueueDuringDispatch?.(this.opts.runtimeKey, buildEventBody(event))) {
844
+ this.startInjectedTyping(event);
845
+ this.opts.log?.info(`parall[${this.opts.accountId}]: steer injected for ${event.messageId} (will drain for bookkeeping)`);
846
+ }
847
+ // If the main dispatch cycle ended while we awaited the steer RPC,
848
+ // our event is buffered but no drain is in flight. Re-enter the
849
+ // drain to process it. The draining guard prevents re-entry.
850
+ if (!this.dispatchState.mainDispatching && !this.draining && this.dispatchState.mainBuffer.length > 0) {
851
+ this.dispatchState.mainDispatching = true;
852
+ void this.drainMainBuffer();
809
853
  }
810
- this.dispatchState.mainBuffer.push(event);
811
854
  return false;
812
855
  }
813
856
  case "buffer-fork": {
@@ -910,6 +953,7 @@ export class ParallAgentGateway {
910
953
  threadRootId: message.thread_root_id ?? undefined,
911
954
  noReply: message.hints?.no_reply ?? false,
912
955
  attachments: attachments.length > 0 ? attachments : undefined,
956
+ sentAt: message.created_at,
913
957
  ackSourceType: "message",
914
958
  ackSourceId: message.id,
915
959
  },
@@ -931,9 +975,6 @@ export class ParallAgentGateway {
931
975
  return;
932
976
  }
933
977
  const event = decision.event;
934
- const willDispatch = !this.dispatchState.mainDispatching || this.dispatchState.mainCurrentTargetId !== chatId;
935
- if (willDispatch)
936
- this.startTyping(chatId);
937
978
  try {
938
979
  const dispatched = await this.handleInboundEvent(event);
939
980
  if (dispatched) {
@@ -947,10 +988,6 @@ export class ParallAgentGateway {
947
988
  this.opts.log?.error(`parall[${this.opts.accountId}]: event dispatch failed for ${data.id}: ${String(err)}`);
948
989
  this.dispatchedMessages.delete(data.id);
949
990
  }
950
- finally {
951
- if (willDispatch)
952
- this.stopTyping(chatId);
953
- }
954
991
  }
955
992
  async handleTaskAssignment(task, ackSourceId) {
956
993
  if (this.shuttingDown)
@@ -979,6 +1016,7 @@ export class ParallAgentGateway {
979
1016
  senderName: "system",
980
1017
  messageId: task.id,
981
1018
  body: parts.join("\n"),
1019
+ sentAt: task.updated_at ?? task.created_at,
982
1020
  ackSourceType: "task_activity",
983
1021
  ackSourceId,
984
1022
  };
package/dist/types.d.ts CHANGED
@@ -47,6 +47,9 @@ export type ParallEvent = {
47
47
  scheduledFireAt?: string;
48
48
  /** Fire-time attached_to_uri snapshot, used for schedule events. */
49
49
  attachedUri?: string;
50
+ /** Original event timestamp (e.g., message.created_at). When present,
51
+ * input steps use this instead of server insertion time for ordering. */
52
+ sentAt?: string;
50
53
  ackSourceType?: "message" | "task_activity" | "comment" | "schedule_run";
51
54
  ackSourceId?: string;
52
55
  };
@@ -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,mFAAmF;IACnF,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,sFAAsF;IACtF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qFAAqF;IACrF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,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"}
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,mFAAmF;IACnF,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,sFAAsF;IACtF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qFAAqF;IACrF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,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;8EAC0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,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.29.0",
3
+ "version": "1.29.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.29.0"
29
+ "@parall/sdk": "1.29.2"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@types/node": "^22.0.0",
@@ -68,19 +68,20 @@ export interface DispatchAdapter {
68
68
  dispatch(opts: DispatchOpts): AsyncIterable<RuntimeEvent>;
69
69
 
70
70
  /**
71
- * Inject a user message into the running subprocess's stdin mid-turn so the
72
- * runtime reads it between tool calls and steers immediately, rather than
73
- * waiting for the current turn to complete.
71
+ * Inject a user message into the running runtime mid-turn so it steers
72
+ * immediately, rather than waiting for the current turn to complete.
74
73
  *
75
- * Returns true if the message was successfully written to stdin; false if no
76
- * live process exists for the session (caller should fall back to mainBuffer).
74
+ * Returns true if the injection succeeded; false if no live process/session
75
+ * exists (caller falls back to mainBuffer next-turn path). May return a
76
+ * Promise when the injection requires an async round-trip (e.g. Codex
77
+ * turn/steer JSON-RPC) — the gateway awaits it.
77
78
  *
78
79
  * The gateway still pushes the event to mainBuffer after a successful
79
80
  * injection — drainMainBuffer will call dispatch() for it, and dispatch()
80
- * must detect the pending injection (skip the stdin write) and only consume
81
- * the parser output that Claude produced in response.
81
+ * must detect the pending injection (skip the duplicate input) and only
82
+ * consume output produced in response.
82
83
  */
83
- enqueueDuringDispatch?(sessionKey: string, body: string): boolean;
84
+ enqueueDuringDispatch?(sessionKey: string, body: string): boolean | Promise<boolean>;
84
85
 
85
86
  /** True if enqueueDuringDispatch was called and the injections have not yet been consumed by dispatch(). */
86
87
  hasPendingInjections?(sessionKey: string): boolean;
@@ -71,6 +71,7 @@ type DispatchableMessage = {
71
71
  thread_root_id?: string | null;
72
72
  hints?: { no_reply?: boolean } | null;
73
73
  attachments?: Array<{ id: string; file_name: string; file_size: number; mime_type: string }>;
74
+ created_at?: string;
74
75
  };
75
76
 
76
77
  type MessageDispatchDecision =
@@ -169,6 +170,7 @@ async function fetchAllChats(
169
170
  export class ParallAgentGateway {
170
171
  private readonly chatInfoMap = new Map<string, ChatInfo>();
171
172
  private readonly activeDispatches = new Map<string, ActiveDispatch>();
173
+ private readonly injectedTypingCounts = new Map<string, number>();
172
174
  private readonly dispatchedTasks = new Set<string>();
173
175
  private readonly dispatchedMessages = new Set<string>();
174
176
  private readonly forkStates = new Map<string, ActiveForkState>();
@@ -376,6 +378,42 @@ export class ParallAgentGateway {
376
378
  if (this.opts.ws.state === "connected") this.opts.ws.sendTyping(chatId, "stop");
377
379
  }
378
380
 
381
+ private shouldShowTyping(event: ParallEvent): boolean {
382
+ return event.type === "message" && event.targetId.startsWith("cht_") && !event.noReply;
383
+ }
384
+
385
+ private startInjectedTyping(event: ParallEvent) {
386
+ if (!this.shouldShowTyping(event)) return;
387
+ this.startTyping(event.targetId);
388
+ this.injectedTypingCounts.set(event.targetId, (this.injectedTypingCounts.get(event.targetId) ?? 0) + 1);
389
+ }
390
+
391
+ private takeInjectedTypingCount(chatId: string): number {
392
+ const count = this.injectedTypingCounts.get(chatId) ?? 0;
393
+ this.injectedTypingCounts.delete(chatId);
394
+ return count;
395
+ }
396
+
397
+ private async runDispatchWithTyping(
398
+ event: ParallEvent,
399
+ sessionKey: string,
400
+ bodyForAgent: string,
401
+ earlierEvents: ParallEvent[] = [],
402
+ captureText?: string[],
403
+ opts: { suppressStart?: boolean; injectedTypingCount?: number } = {},
404
+ ): Promise<boolean> {
405
+ const showTyping = !opts.suppressStart && (this.shouldShowTyping(event) || earlierEvents.some(e => this.shouldShowTyping(e)));
406
+ if (showTyping) this.startTyping(event.targetId);
407
+ try {
408
+ return await this.runDispatch(event, sessionKey, bodyForAgent, earlierEvents, captureText);
409
+ } finally {
410
+ if (showTyping) this.stopTyping(event.targetId);
411
+ for (let i = 0; i < (opts.injectedTypingCount ?? 0); i++) {
412
+ this.stopTyping(event.targetId);
413
+ }
414
+ }
415
+ }
416
+
379
417
  private buildDispatchContext(event: ParallEvent, sessionKey: string): DispatchContext {
380
418
  const binding = this.sessionBindings.get(sessionKey);
381
419
  return {
@@ -420,6 +458,7 @@ export class ParallAgentGateway {
420
458
  sender_id: event.senderId,
421
459
  sender_name: event.senderName,
422
460
  summary: event.body.substring(0, 200),
461
+ ...(event.sentAt ? { sent_at: event.sentAt } : {}),
423
462
  },
424
463
  });
425
464
  } catch (err) {
@@ -778,7 +817,7 @@ export class ParallAgentGateway {
778
817
  const earlier = events.slice(0, -1);
779
818
  try {
780
819
  const batchText: string[] = [];
781
- const dispatched = await this.runDispatch(last, fork.fork.sessionKey, buildForkScopePrefix(last) + buildEventBody(last), earlier, batchText);
820
+ const dispatched = await this.runDispatchWithTyping(last, fork.fork.sessionKey, buildForkScopePrefix(last) + buildEventBody(last), earlier, batchText);
782
821
  if (!dispatched) {
783
822
  // Shutdown short-circuit — resolve un-acked so the server requeues
784
823
  // for the replacement pod and stop draining further items.
@@ -885,13 +924,21 @@ export class ParallAgentGateway {
885
924
 
886
925
  const event = events[events.length - 1];
887
926
  const earlier = events.slice(0, -1);
888
- const skipForkSplice = this.opts.dispatchAdapter.hasPendingInjections?.(this.opts.runtimeKey) ?? false;
889
- const pendingFork = skipForkSplice ? [] : this.dispatchState.pendingForkResults.splice(0);
927
+ const hasPendingInjections = this.opts.dispatchAdapter.hasPendingInjections?.(this.opts.runtimeKey) ?? false;
928
+ const injectedTypingCount = hasPendingInjections ? this.takeInjectedTypingCount(event.targetId) : 0;
929
+ const pendingFork = hasPendingInjections ? [] : this.dispatchState.pendingForkResults.splice(0);
890
930
  const forkPrefix = buildForkResultPrefix(pendingFork);
891
931
  this.dispatchState.mainCurrentTargetId = event.targetId;
892
932
  this.dispatchState.mainPreDispatchBranchPoint =
893
933
  this.opts.dispatchAdapter.getBranchPoint?.(this.opts.runtimeKey);
894
- const dispatched = await this.runDispatch(event, this.opts.runtimeKey, forkPrefix + buildEventBody(event), earlier);
934
+ const dispatched = await this.runDispatchWithTyping(
935
+ event,
936
+ this.opts.runtimeKey,
937
+ forkPrefix + buildEventBody(event),
938
+ earlier,
939
+ undefined,
940
+ { suppressStart: injectedTypingCount > 0, injectedTypingCount },
941
+ );
895
942
  if (!dispatched) {
896
943
  // Shutdown: skip the ack so the server redelivers these buffered
897
944
  // events to the replacement pod via dispatch catch-up. Put both the
@@ -933,7 +980,7 @@ export class ParallAgentGateway {
933
980
  this.opts.dispatchAdapter.getBranchPoint?.(this.opts.runtimeKey);
934
981
  let dispatched = false;
935
982
  try {
936
- dispatched = await this.runDispatch(event, this.opts.runtimeKey, forkPrefix + buildEventBody(event));
983
+ dispatched = await this.runDispatchWithTyping(event, this.opts.runtimeKey, forkPrefix + buildEventBody(event));
937
984
  if (!dispatched) {
938
985
  // Shutdown short-circuit — restore the fork results so a future
939
986
  // pod can replay them, and return false so handleMessage skips ack.
@@ -949,15 +996,26 @@ export class ParallAgentGateway {
949
996
  if (this.shuttingDown) {
950
997
  return false;
951
998
  }
999
+ // Push synchronously BEFORE the (possibly async) steer attempt so
1000
+ // arrival order is preserved and the event cannot be orphaned in a
1001
+ // gap between the steer await and the push.
1002
+ this.dispatchState.mainBuffer.push(event);
952
1003
  if (
953
1004
  this.dispatchState.mainCurrentTargetId === event.targetId &&
954
- this.opts.dispatchAdapter.enqueueDuringDispatch?.(this.opts.runtimeKey, buildEventBody(event))
1005
+ await this.opts.dispatchAdapter.enqueueDuringDispatch?.(this.opts.runtimeKey, buildEventBody(event))
955
1006
  ) {
1007
+ this.startInjectedTyping(event);
956
1008
  this.opts.log?.info(
957
- `parall[${this.opts.accountId}]: steer injected to stdin for ${event.messageId} (will drain for bookkeeping)`,
1009
+ `parall[${this.opts.accountId}]: steer injected for ${event.messageId} (will drain for bookkeeping)`,
958
1010
  );
959
1011
  }
960
- this.dispatchState.mainBuffer.push(event);
1012
+ // If the main dispatch cycle ended while we awaited the steer RPC,
1013
+ // our event is buffered but no drain is in flight. Re-enter the
1014
+ // drain to process it. The draining guard prevents re-entry.
1015
+ if (!this.dispatchState.mainDispatching && !this.draining && this.dispatchState.mainBuffer.length > 0) {
1016
+ this.dispatchState.mainDispatching = true;
1017
+ void this.drainMainBuffer();
1018
+ }
961
1019
  return false;
962
1020
  }
963
1021
 
@@ -1074,6 +1132,7 @@ export class ParallAgentGateway {
1074
1132
  threadRootId: message.thread_root_id ?? undefined,
1075
1133
  noReply: message.hints?.no_reply ?? false,
1076
1134
  attachments: attachments.length > 0 ? attachments : undefined,
1135
+ sentAt: message.created_at,
1077
1136
  ackSourceType: "message",
1078
1137
  ackSourceId: message.id,
1079
1138
  },
@@ -1094,8 +1153,6 @@ export class ParallAgentGateway {
1094
1153
  }
1095
1154
  const event = decision.event;
1096
1155
 
1097
- const willDispatch = !this.dispatchState.mainDispatching || this.dispatchState.mainCurrentTargetId !== chatId;
1098
- if (willDispatch) this.startTyping(chatId);
1099
1156
  try {
1100
1157
  const dispatched = await this.handleInboundEvent(event);
1101
1158
  if (dispatched) {
@@ -1106,8 +1163,6 @@ export class ParallAgentGateway {
1106
1163
  } catch (err) {
1107
1164
  this.opts.log?.error(`parall[${this.opts.accountId}]: event dispatch failed for ${data.id}: ${String(err)}`);
1108
1165
  this.dispatchedMessages.delete(data.id);
1109
- } finally {
1110
- if (willDispatch) this.stopTyping(chatId);
1111
1166
  }
1112
1167
  }
1113
1168
 
@@ -1136,6 +1191,7 @@ export class ParallAgentGateway {
1136
1191
  senderName: "system",
1137
1192
  messageId: task.id,
1138
1193
  body: parts.join("\n"),
1194
+ sentAt: task.updated_at ?? task.created_at,
1139
1195
  ackSourceType: "task_activity",
1140
1196
  ackSourceId,
1141
1197
  };
package/src/types.ts CHANGED
@@ -45,6 +45,9 @@ export type ParallEvent = {
45
45
  scheduledFireAt?: string;
46
46
  /** Fire-time attached_to_uri snapshot, used for schedule events. */
47
47
  attachedUri?: string;
48
+ /** Original event timestamp (e.g., message.created_at). When present,
49
+ * input steps use this instead of server insertion time for ordering. */
50
+ sentAt?: string;
48
51
  ackSourceType?: "message" | "task_activity" | "comment" | "schedule_run";
49
52
  ackSourceId?: string;
50
53
  };