@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.
- package/dist/dispatch-adapter.d.ts +9 -8
- package/dist/dispatch-adapter.d.ts.map +1 -1
- package/dist/gateway-base.d.ts +5 -0
- package/dist/gateway-base.d.ts.map +1 -1
- package/dist/gateway-base.js +53 -15
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/dispatch-adapter.ts +9 -8
- package/src/gateway-base.ts +68 -12
- package/src/types.ts +3 -0
|
@@ -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
|
|
84
|
-
*
|
|
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
|
|
88
|
-
*
|
|
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
|
|
93
|
-
*
|
|
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":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gFAAgF;IAChF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,YAAY,CAAC;IACrB,GAAG,CAAC,EAAE,aAAa,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,YAAY,GACpB;IACE,IAAI,EAAE,iBAAiB,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC,GACD;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9G;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GACjI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvC,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,WAAW,CAAC;IACnB,aAAa,CAAC,EAAE,WAAW,EAAE,CAAC;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,eAAe,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,eAAe,CAAC;IACzB,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,iBAAiB,CAAC;IACxB,OAAO,EAAE,eAAe,CAAC;CAC1B,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B,iFAAiF;IACjF,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,aAAa,CAAC,YAAY,CAAC,CAAC;IAE1D
|
|
1
|
+
{"version":3,"file":"dispatch-adapter.d.ts","sourceRoot":"","sources":["../src/dispatch-adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/gateway-base.d.ts
CHANGED
|
@@ -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":"AAGA,OAAO,EAAuB,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,KAAK,EACV,qBAAqB,EActB,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAEV,eAAe,EAGf,aAAa,EAEd,MAAM,uBAAuB,CAAC;
|
|
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
|
@@ -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.
|
|
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
|
|
744
|
-
const
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
};
|
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,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.
|
|
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.
|
|
29
|
+
"@parall/sdk": "1.29.2"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@types/node": "^22.0.0",
|
package/src/dispatch-adapter.ts
CHANGED
|
@@ -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
|
|
72
|
-
*
|
|
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
|
|
76
|
-
*
|
|
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
|
|
81
|
-
*
|
|
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;
|
package/src/gateway-base.ts
CHANGED
|
@@ -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.
|
|
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
|
|
889
|
-
const
|
|
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.
|
|
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.
|
|
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
|
|
1009
|
+
`parall[${this.opts.accountId}]: steer injected for ${event.messageId} (will drain for bookkeeping)`,
|
|
958
1010
|
);
|
|
959
1011
|
}
|
|
960
|
-
|
|
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
|
};
|