@parall/agent-core 1.29.3 → 1.30.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.
- package/dist/dispatch-adapter.d.ts +1 -0
- package/dist/dispatch-adapter.d.ts.map +1 -1
- package/dist/gateway-base.d.ts +2 -0
- package/dist/gateway-base.d.ts.map +1 -1
- package/dist/gateway-base.js +73 -53
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/logger.d.ts +1 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +4 -0
- package/package.json +2 -2
- package/src/dispatch-adapter.ts +1 -0
- package/src/gateway-base.ts +76 -53
- package/src/index.ts +1 -1
- package/src/logger.ts +5 -0
|
@@ -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;
|
|
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
|
@@ -35,6 +35,7 @@ export type ParallGatewayOptions = {
|
|
|
35
35
|
runtimeLaneKey: string;
|
|
36
36
|
}) => Promise<void> | void;
|
|
37
37
|
onBeforeDisconnect?: () => Promise<void> | void;
|
|
38
|
+
onNewSession?: (previousSessionId: string) => Promise<void> | void;
|
|
38
39
|
};
|
|
39
40
|
export declare function parseShutdownDeadlineMs(raw: string | undefined): number | undefined;
|
|
40
41
|
export declare class ParallAgentGateway {
|
|
@@ -56,6 +57,7 @@ export declare class ParallAgentGateway {
|
|
|
56
57
|
private shuttingDown;
|
|
57
58
|
private inFlightDispatches;
|
|
58
59
|
private drainResolvers;
|
|
60
|
+
private pendingRestartNotification;
|
|
59
61
|
private readonly DISPATCHED_MESSAGES_CAP;
|
|
60
62
|
private readonly COLD_START_WINDOW_MS;
|
|
61
63
|
private readonly SHUTDOWN_DEADLINE_MS;
|
|
@@ -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,
|
|
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
|
@@ -78,6 +78,7 @@ export class ParallAgentGateway {
|
|
|
78
78
|
shuttingDown = false;
|
|
79
79
|
inFlightDispatches = 0;
|
|
80
80
|
drainResolvers = [];
|
|
81
|
+
pendingRestartNotification = null;
|
|
81
82
|
DISPATCHED_MESSAGES_CAP = 5000;
|
|
82
83
|
COLD_START_WINDOW_MS;
|
|
83
84
|
// SHUTDOWN_DEADLINE_MS is read by waitForDrain via the configured value
|
|
@@ -92,7 +93,7 @@ export class ParallAgentGateway {
|
|
|
92
93
|
async run(abortSignal) {
|
|
93
94
|
const { ws, log } = this.opts;
|
|
94
95
|
ws.onStateChange((state) => {
|
|
95
|
-
log?.info(`
|
|
96
|
+
log?.info(`connection state → ${state}`);
|
|
96
97
|
});
|
|
97
98
|
ws.on("hello", async (data) => {
|
|
98
99
|
await this.handleHello(data);
|
|
@@ -126,17 +127,32 @@ export class ParallAgentGateway {
|
|
|
126
127
|
await this.handleMessage(data);
|
|
127
128
|
});
|
|
128
129
|
ws.on("agent_config.update", async (data) => {
|
|
129
|
-
this.opts.log?.info(`
|
|
130
|
+
this.opts.log?.info(`config update notification (version=${data.version})`);
|
|
130
131
|
try {
|
|
131
132
|
await this.opts.onConfigUpdate?.(data);
|
|
132
133
|
}
|
|
133
134
|
catch (err) {
|
|
134
|
-
this.opts.log?.warn(`
|
|
135
|
+
this.opts.log?.warn(`config update failed: ${String(err)}`);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
ws.on("agent.new_session", async (data) => {
|
|
139
|
+
const prevId = data.previous_session_id ?? "";
|
|
140
|
+
this.opts.log?.info(`new session signal received (previous=${prevId})`);
|
|
141
|
+
this.sessionBindings.clear();
|
|
142
|
+
if (prevId) {
|
|
143
|
+
this.pendingRestartNotification =
|
|
144
|
+
`[Harness Notification] This is a fresh session. Your previous session (${prevId}) was ended by the user and you have been restarted.`;
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
await this.opts.onNewSession?.(prevId);
|
|
148
|
+
}
|
|
149
|
+
catch (err) {
|
|
150
|
+
this.opts.log?.warn(`onNewSession callback failed: ${String(err)}`);
|
|
135
151
|
}
|
|
136
152
|
});
|
|
137
153
|
ws.on("recovery.overflow", () => {
|
|
138
|
-
this.opts.log?.warn(`
|
|
139
|
-
this.catchUpFromDispatch().catch((err) => this.opts.log?.warn(`
|
|
154
|
+
this.opts.log?.warn(`recovery.overflow — triggering full catch-up`);
|
|
155
|
+
this.catchUpFromDispatch().catch((err) => this.opts.log?.warn(`overflow catch-up failed: ${String(err)}`));
|
|
140
156
|
});
|
|
141
157
|
ws.on("task.assigned", async (data) => {
|
|
142
158
|
if (data.assignee_id !== this.opts.agentUserId)
|
|
@@ -150,7 +166,7 @@ export class ParallAgentGateway {
|
|
|
150
166
|
}
|
|
151
167
|
}
|
|
152
168
|
catch (err) {
|
|
153
|
-
this.opts.log?.error(`
|
|
169
|
+
this.opts.log?.error(`task dispatch failed for ${data.id}: ${String(err)}`);
|
|
154
170
|
}
|
|
155
171
|
});
|
|
156
172
|
ws.on("dispatch.new", async (data) => {
|
|
@@ -164,7 +180,7 @@ export class ParallAgentGateway {
|
|
|
164
180
|
}
|
|
165
181
|
}
|
|
166
182
|
catch (err) {
|
|
167
|
-
this.opts.log?.error(`
|
|
183
|
+
this.opts.log?.error(`task comment dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
168
184
|
}
|
|
169
185
|
}
|
|
170
186
|
else if (data.event_type === "task_update") {
|
|
@@ -177,7 +193,7 @@ export class ParallAgentGateway {
|
|
|
177
193
|
}
|
|
178
194
|
}
|
|
179
195
|
catch (err) {
|
|
180
|
-
this.opts.log?.error(`
|
|
196
|
+
this.opts.log?.error(`task update dispatch failed for ${data.task_id}: ${String(err)}`);
|
|
181
197
|
}
|
|
182
198
|
}
|
|
183
199
|
else if (data.event_type === "schedule.fire") {
|
|
@@ -190,7 +206,7 @@ export class ParallAgentGateway {
|
|
|
190
206
|
}
|
|
191
207
|
}
|
|
192
208
|
catch (err) {
|
|
193
|
-
this.opts.log?.error(`
|
|
209
|
+
this.opts.log?.error(`schedule fire dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
194
210
|
}
|
|
195
211
|
}
|
|
196
212
|
else if (data.event_type === "approval_decided") {
|
|
@@ -203,7 +219,7 @@ export class ParallAgentGateway {
|
|
|
203
219
|
}
|
|
204
220
|
}
|
|
205
221
|
catch (err) {
|
|
206
|
-
this.opts.log?.error(`
|
|
222
|
+
this.opts.log?.error(`approval decided dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
207
223
|
}
|
|
208
224
|
}
|
|
209
225
|
else if (data.event_type !== "message" && data.event_type !== "task_assign") {
|
|
@@ -214,10 +230,10 @@ export class ParallAgentGateway {
|
|
|
214
230
|
// (message.new, task.assigned) above and would otherwise spam
|
|
215
231
|
// info-level logs for every inbound chat message / task
|
|
216
232
|
// assignment on a busy agent.
|
|
217
|
-
this.opts.log?.info(`
|
|
233
|
+
this.opts.log?.info(`dispatch.new with unhandled event_type=${String(data.event_type)} (id=${data.id}) — no-op`);
|
|
218
234
|
}
|
|
219
235
|
});
|
|
220
|
-
this.opts.log?.info(`
|
|
236
|
+
this.opts.log?.info(`connecting to ${this.opts.connectionLabel ?? "Parall WS"}...`);
|
|
221
237
|
await ws.connect();
|
|
222
238
|
return new Promise((resolve) => {
|
|
223
239
|
abortSignal.addEventListener("abort", async () => {
|
|
@@ -341,7 +357,7 @@ export class ParallAgentGateway {
|
|
|
341
357
|
});
|
|
342
358
|
}
|
|
343
359
|
catch (err) {
|
|
344
|
-
this.opts.log?.warn(`
|
|
360
|
+
this.opts.log?.warn(`failed to create input step: ${String(err)}`);
|
|
345
361
|
}
|
|
346
362
|
}
|
|
347
363
|
async createRuntimeStep(sessionId, event, runtimeEvent, stepIdFilePath, contextFilePath) {
|
|
@@ -421,13 +437,13 @@ export class ParallAgentGateway {
|
|
|
421
437
|
target_type: target.target_type,
|
|
422
438
|
target_id: target.target_id,
|
|
423
439
|
content: { text: runtimeEvent.message, suppressed: false },
|
|
424
|
-
projection:
|
|
440
|
+
projection: false,
|
|
425
441
|
});
|
|
426
442
|
break;
|
|
427
443
|
}
|
|
428
444
|
}
|
|
429
445
|
catch (err) {
|
|
430
|
-
this.opts.log?.warn(`
|
|
446
|
+
this.opts.log?.warn(`failed to create ${runtimeEvent.type} step: ${String(err)}`);
|
|
431
447
|
}
|
|
432
448
|
}
|
|
433
449
|
writeContextFile(filePath, ctx) {
|
|
@@ -436,7 +452,7 @@ export class ParallAgentGateway {
|
|
|
436
452
|
fs.writeFileSync(filePath, JSON.stringify(ctx), "utf8");
|
|
437
453
|
}
|
|
438
454
|
catch (err) {
|
|
439
|
-
this.opts.log?.warn(`
|
|
455
|
+
this.opts.log?.warn(`failed to write context file ${filePath}: ${String(err)}`);
|
|
440
456
|
}
|
|
441
457
|
}
|
|
442
458
|
updateContextFileStepId(filePath, stepId) {
|
|
@@ -447,7 +463,7 @@ export class ParallAgentGateway {
|
|
|
447
463
|
fs.writeFileSync(filePath, JSON.stringify(ctx), "utf8");
|
|
448
464
|
}
|
|
449
465
|
catch (err) {
|
|
450
|
-
this.opts.log?.warn(`
|
|
466
|
+
this.opts.log?.warn(`failed to update context file step_id ${filePath}: ${String(err)}`);
|
|
451
467
|
}
|
|
452
468
|
}
|
|
453
469
|
updateContextFileSessionId(filePath, sessionId) {
|
|
@@ -458,7 +474,7 @@ export class ParallAgentGateway {
|
|
|
458
474
|
fs.writeFileSync(filePath, JSON.stringify(ctx), "utf8");
|
|
459
475
|
}
|
|
460
476
|
catch (err) {
|
|
461
|
-
this.opts.log?.warn(`
|
|
477
|
+
this.opts.log?.warn(`failed to update context file session_id ${filePath}: ${String(err)}`);
|
|
462
478
|
}
|
|
463
479
|
}
|
|
464
480
|
/** @deprecated Use writeContextFile / updateContextFileStepId. */
|
|
@@ -468,7 +484,7 @@ export class ParallAgentGateway {
|
|
|
468
484
|
fs.writeFileSync(filePath, stepId, "utf8");
|
|
469
485
|
}
|
|
470
486
|
catch (err) {
|
|
471
|
-
this.opts.log?.warn(`
|
|
487
|
+
this.opts.log?.warn(`failed to write step id file ${filePath}: ${String(err)}`);
|
|
472
488
|
}
|
|
473
489
|
}
|
|
474
490
|
/** @deprecated Use writeContextFile / updateContextFileStepId. */
|
|
@@ -534,9 +550,13 @@ export class ParallAgentGateway {
|
|
|
534
550
|
// In-flight dispatches that started before the flag flipped keep running
|
|
535
551
|
// and are awaited by shutdown() up to SHUTDOWN_DEADLINE_MS.
|
|
536
552
|
if (this.shuttingDown) {
|
|
537
|
-
this.opts.log?.info(`
|
|
553
|
+
this.opts.log?.info(`skipping dispatch for ${event.messageId} (shutting down) — leaving unacked for catch-up on replacement pod`);
|
|
538
554
|
return false;
|
|
539
555
|
}
|
|
556
|
+
if (this.pendingRestartNotification) {
|
|
557
|
+
bodyForAgent = this.pendingRestartNotification + "\n\n---\n\n" + bodyForAgent;
|
|
558
|
+
this.pendingRestartNotification = null;
|
|
559
|
+
}
|
|
540
560
|
setSessionChatId(sessionKey, event.targetId);
|
|
541
561
|
setSessionMessageId(sessionKey, event.messageId);
|
|
542
562
|
setDispatchMessageId(sessionKey, event.messageId);
|
|
@@ -685,7 +705,7 @@ export class ParallAgentGateway {
|
|
|
685
705
|
}
|
|
686
706
|
}
|
|
687
707
|
catch (err) {
|
|
688
|
-
this.opts.log?.error(`
|
|
708
|
+
this.opts.log?.error(`fork dispatch failed for ${last.messageId}: ${String(err)}`);
|
|
689
709
|
for (const item of items) {
|
|
690
710
|
item.resolve(false);
|
|
691
711
|
}
|
|
@@ -705,7 +725,7 @@ export class ParallAgentGateway {
|
|
|
705
725
|
historyPath = this.opts.dispatchAdapter.getSessionHistoryPath?.(fork.fork.sessionKey);
|
|
706
726
|
}
|
|
707
727
|
catch (err) {
|
|
708
|
-
this.opts.log?.warn?.(`
|
|
728
|
+
this.opts.log?.warn?.(`failed to resolve fork history path: ${String(err)}`);
|
|
709
729
|
}
|
|
710
730
|
this.dispatchState.pendingForkResults.push({
|
|
711
731
|
forkSessionKey: fork.fork.sessionKey,
|
|
@@ -761,7 +781,7 @@ export class ParallAgentGateway {
|
|
|
761
781
|
// pendingForkResults intact so dispatch catch-up on the replacement
|
|
762
782
|
// pod is the single source of truth for replay.
|
|
763
783
|
if (this.shuttingDown) {
|
|
764
|
-
this.opts.log?.info(`
|
|
784
|
+
this.opts.log?.info(`drainMainBuffer halted (shutting down) — ${this.dispatchState.mainBuffer.length} buffered, ${this.dispatchState.pendingForkResults.length} pending fork results left for catch-up`);
|
|
765
785
|
break;
|
|
766
786
|
}
|
|
767
787
|
const targetId = this.dispatchState.mainBuffer[0].targetId;
|
|
@@ -842,7 +862,7 @@ export class ParallAgentGateway {
|
|
|
842
862
|
if (this.dispatchState.mainCurrentTargetId === event.targetId &&
|
|
843
863
|
await this.opts.dispatchAdapter.enqueueDuringDispatch?.(this.opts.runtimeKey, buildEventBody(event))) {
|
|
844
864
|
this.startInjectedTyping(event);
|
|
845
|
-
this.opts.log?.info(`
|
|
865
|
+
this.opts.log?.info(`steer injected for ${event.messageId} (will drain for bookkeeping)`);
|
|
846
866
|
}
|
|
847
867
|
// If the main dispatch cycle ended while we awaited the steer RPC,
|
|
848
868
|
// our event is buffered but no drain is in flight. Re-enter the
|
|
@@ -874,7 +894,7 @@ export class ParallAgentGateway {
|
|
|
874
894
|
preDispatchBranchPoint: this.dispatchState.mainPreDispatchBranchPoint,
|
|
875
895
|
});
|
|
876
896
|
if (!fork) {
|
|
877
|
-
this.opts.log?.warn(`
|
|
897
|
+
this.opts.log?.warn(`fork failed, buffering event for main session`);
|
|
878
898
|
this.dispatchState.mainBuffer.push(event);
|
|
879
899
|
return false;
|
|
880
900
|
}
|
|
@@ -890,7 +910,7 @@ export class ParallAgentGateway {
|
|
|
890
910
|
activeFork.queue.push({ event, resolve });
|
|
891
911
|
});
|
|
892
912
|
this.runForkDrainLoop(activeFork).catch((err) => {
|
|
893
|
-
this.opts.log?.error(`
|
|
913
|
+
this.opts.log?.error(`fork drain loop error: ${String(err)}`);
|
|
894
914
|
});
|
|
895
915
|
return firstEventPromise;
|
|
896
916
|
}
|
|
@@ -911,7 +931,7 @@ export class ParallAgentGateway {
|
|
|
911
931
|
return chatInfo;
|
|
912
932
|
}
|
|
913
933
|
catch (err) {
|
|
914
|
-
this.opts.log?.warn(`
|
|
934
|
+
this.opts.log?.warn(`failed to resolve chat ${chatId}: ${String(err)}`);
|
|
915
935
|
return null;
|
|
916
936
|
}
|
|
917
937
|
}
|
|
@@ -985,7 +1005,7 @@ export class ParallAgentGateway {
|
|
|
985
1005
|
}
|
|
986
1006
|
}
|
|
987
1007
|
catch (err) {
|
|
988
|
-
this.opts.log?.error(`
|
|
1008
|
+
this.opts.log?.error(`event dispatch failed for ${data.id}: ${String(err)}`);
|
|
989
1009
|
this.dispatchedMessages.delete(data.id);
|
|
990
1010
|
}
|
|
991
1011
|
}
|
|
@@ -994,11 +1014,11 @@ export class ParallAgentGateway {
|
|
|
994
1014
|
return false; // drain window — let server requeue via catch-up
|
|
995
1015
|
const dedupeKey = `${task.id}:${task.updated_at}`;
|
|
996
1016
|
if (this.dispatchedTasks.has(dedupeKey)) {
|
|
997
|
-
this.opts.log?.info(`
|
|
1017
|
+
this.opts.log?.info(`skipping already-dispatched task ${task.identifier ?? task.id}`);
|
|
998
1018
|
return false;
|
|
999
1019
|
}
|
|
1000
1020
|
this.dispatchedTasks.add(dedupeKey);
|
|
1001
|
-
this.opts.log?.info(`
|
|
1021
|
+
this.opts.log?.info(`task assigned: ${task.identifier ?? task.id} "${task.title}"`);
|
|
1002
1022
|
const parts = [`Title: ${task.title}`];
|
|
1003
1023
|
parts.push(`Status: ${task.status}`, `Priority: ${task.priority}`);
|
|
1004
1024
|
if (task.project_id)
|
|
@@ -1040,7 +1060,7 @@ export class ParallAgentGateway {
|
|
|
1040
1060
|
const isAssignee = task.assignee_id === this.opts.agentUserId;
|
|
1041
1061
|
const isCreatorUpdate = opts.allowCreator === true && task.creator_id === this.opts.agentUserId;
|
|
1042
1062
|
if (!isAssignee && !isCreatorUpdate) {
|
|
1043
|
-
this.opts.log?.info(`
|
|
1063
|
+
this.opts.log?.info(`skipping stale task dispatch ${ackSourceId ?? taskId} — assigned to ${task.assignee_id}, creator ${task.creator_id}`);
|
|
1044
1064
|
return true;
|
|
1045
1065
|
}
|
|
1046
1066
|
return this.handleTaskAssignment(task, ackSourceId);
|
|
@@ -1060,7 +1080,7 @@ export class ParallAgentGateway {
|
|
|
1060
1080
|
const status = err?.status;
|
|
1061
1081
|
if (status === 404) {
|
|
1062
1082
|
// Comment deleted — ack stale dispatch so it doesn't pile up.
|
|
1063
|
-
this.opts.log?.info(`
|
|
1083
|
+
this.opts.log?.info(`skipping deleted comment ${commentId}, acking stale dispatch`);
|
|
1064
1084
|
this.dispatchedTasks.delete(dedupeKey);
|
|
1065
1085
|
return true; // caller will ack
|
|
1066
1086
|
}
|
|
@@ -1072,7 +1092,7 @@ export class ParallAgentGateway {
|
|
|
1072
1092
|
return true; // null response = gone, ack stale dispatch
|
|
1073
1093
|
}
|
|
1074
1094
|
if (comment.hints?.no_reply) {
|
|
1075
|
-
this.opts.log?.info(`
|
|
1095
|
+
this.opts.log?.info(`skipping no_reply task comment ${commentId}, acking stale dispatch`);
|
|
1076
1096
|
this.dispatchedTasks.delete(dedupeKey);
|
|
1077
1097
|
return true;
|
|
1078
1098
|
}
|
|
@@ -1082,7 +1102,7 @@ export class ParallAgentGateway {
|
|
|
1082
1102
|
}
|
|
1083
1103
|
catch { /* task context is optional */ }
|
|
1084
1104
|
const taskLabel = task ? `${task.identifier ?? task.id} "${task.title}"` : taskId;
|
|
1085
|
-
this.opts.log?.info(`
|
|
1105
|
+
this.opts.log?.info(`task comment on ${taskLabel} by ${actorId ?? "unknown"}`);
|
|
1086
1106
|
const parts = [];
|
|
1087
1107
|
if (task) {
|
|
1088
1108
|
parts.push(`Task: ${task.title} (prll://${task.id})`);
|
|
@@ -1141,10 +1161,10 @@ export class ParallAgentGateway {
|
|
|
1141
1161
|
// already-delivered run — this is expected but operationally
|
|
1142
1162
|
// visible, so warn (not info) keeps it findable during incident
|
|
1143
1163
|
// triage. See docs/primitives/schedule.md § Snapshot 不变性.
|
|
1144
|
-
this.opts.log?.warn(`
|
|
1164
|
+
this.opts.log?.warn(`schedule run ${runId} not accessible (404), acking stale dispatch`);
|
|
1145
1165
|
return true;
|
|
1146
1166
|
}
|
|
1147
|
-
this.opts.log?.warn(`
|
|
1167
|
+
this.opts.log?.warn(`schedule run fetch failed for ${runId}, leaving pending: ${String(err)}`);
|
|
1148
1168
|
return false;
|
|
1149
1169
|
}
|
|
1150
1170
|
if (!run)
|
|
@@ -1158,7 +1178,7 @@ export class ParallAgentGateway {
|
|
|
1158
1178
|
if (this.dispatchedTasks.has(dedupeKey))
|
|
1159
1179
|
return false;
|
|
1160
1180
|
this.dispatchedTasks.add(dedupeKey);
|
|
1161
|
-
this.opts.log?.info(`
|
|
1181
|
+
this.opts.log?.info(`schedule fired: ${run.id} (schedule ${run.schedule_id})`);
|
|
1162
1182
|
const event = {
|
|
1163
1183
|
type: "schedule",
|
|
1164
1184
|
// Route by schedule_id (not attached chat_id) so concurrent fires of
|
|
@@ -1197,10 +1217,10 @@ export class ParallAgentGateway {
|
|
|
1197
1217
|
catch (err) {
|
|
1198
1218
|
const status = err?.status;
|
|
1199
1219
|
if (status === 404 || status === 403) {
|
|
1200
|
-
this.opts.log?.warn(`
|
|
1220
|
+
this.opts.log?.warn(`approval ${approvalId} not accessible (${status}), acking stale dispatch`);
|
|
1201
1221
|
return true;
|
|
1202
1222
|
}
|
|
1203
|
-
this.opts.log?.warn(`
|
|
1223
|
+
this.opts.log?.warn(`approval fetch failed for ${approvalId}, leaving pending: ${String(err)}`);
|
|
1204
1224
|
return false;
|
|
1205
1225
|
}
|
|
1206
1226
|
if (!approval)
|
|
@@ -1211,7 +1231,7 @@ export class ParallAgentGateway {
|
|
|
1211
1231
|
if (this.dispatchedTasks.has(dedupeKey))
|
|
1212
1232
|
return false;
|
|
1213
1233
|
this.dispatchedTasks.add(dedupeKey);
|
|
1214
|
-
this.opts.log?.info(`
|
|
1234
|
+
this.opts.log?.info(`approval decided: ${approval.id} (${approval.status})`);
|
|
1215
1235
|
const statusLabel = approval.status === "approved" ? "Approved" : "Rejected";
|
|
1216
1236
|
const execInfo = approval.execution_status ? ` | execution: ${approval.execution_status}` : "";
|
|
1217
1237
|
const body = `${statusLabel}: ${approval.title}${execInfo}`;
|
|
@@ -1264,7 +1284,7 @@ export class ParallAgentGateway {
|
|
|
1264
1284
|
dispatched = await this.handleTaskDispatch(item.task_id, item.source_id ?? item.task_id);
|
|
1265
1285
|
}
|
|
1266
1286
|
catch (err) {
|
|
1267
|
-
this.opts.log?.warn(`
|
|
1287
|
+
this.opts.log?.warn(`catch-up task fetch failed for ${item.task_id}, leaving pending: ${String(err)}`);
|
|
1268
1288
|
continue;
|
|
1269
1289
|
}
|
|
1270
1290
|
}
|
|
@@ -1273,7 +1293,7 @@ export class ParallAgentGateway {
|
|
|
1273
1293
|
dispatched = await this.handleTaskDispatch(item.task_id, item.source_id ?? item.task_id, { allowCreator: true });
|
|
1274
1294
|
}
|
|
1275
1295
|
catch (err) {
|
|
1276
|
-
this.opts.log?.warn(`
|
|
1296
|
+
this.opts.log?.warn(`catch-up task fetch failed for ${item.task_id}, leaving pending: ${String(err)}`);
|
|
1277
1297
|
continue;
|
|
1278
1298
|
}
|
|
1279
1299
|
}
|
|
@@ -1301,7 +1321,7 @@ export class ParallAgentGateway {
|
|
|
1301
1321
|
}
|
|
1302
1322
|
else {
|
|
1303
1323
|
msgFetchFailed = true;
|
|
1304
|
-
this.opts.log?.warn(`
|
|
1324
|
+
this.opts.log?.warn(`catch-up message fetch failed for ${item.source_id}, leaving pending: ${String(err)}`);
|
|
1305
1325
|
}
|
|
1306
1326
|
}
|
|
1307
1327
|
if (msgFetchFailed) {
|
|
@@ -1330,7 +1350,7 @@ export class ParallAgentGateway {
|
|
|
1330
1350
|
}
|
|
1331
1351
|
}
|
|
1332
1352
|
catch (err) {
|
|
1333
|
-
this.opts.log?.warn(`
|
|
1353
|
+
this.opts.log?.warn(`catch-up dispatch ${item.id} (${item.event_type}) failed: ${String(err)}`);
|
|
1334
1354
|
}
|
|
1335
1355
|
}
|
|
1336
1356
|
// Stop paginating once shutdown begins — the inner loop already broke,
|
|
@@ -1338,7 +1358,7 @@ export class ParallAgentGateway {
|
|
|
1338
1358
|
cursor = !this.shuttingDown && page.has_more ? page.next_cursor : undefined;
|
|
1339
1359
|
} while (cursor);
|
|
1340
1360
|
if (processed > 0 || skippedOld > 0) {
|
|
1341
|
-
this.opts.log?.info(`
|
|
1361
|
+
this.opts.log?.info(`dispatch catch-up: processed ${processed}, skipped ${skippedOld} old item(s)`);
|
|
1342
1362
|
}
|
|
1343
1363
|
}
|
|
1344
1364
|
async handleHello(data) {
|
|
@@ -1347,7 +1367,7 @@ export class ParallAgentGateway {
|
|
|
1347
1367
|
const intervalSec = data.heartbeat_interval > 0 ? data.heartbeat_interval : 30;
|
|
1348
1368
|
try {
|
|
1349
1369
|
const count = await fetchAllChats(client, config.org_id, this.chatInfoMap);
|
|
1350
|
-
log?.info(`
|
|
1370
|
+
log?.info(`WebSocket connected, ${count} chats cached`);
|
|
1351
1371
|
await this.opts.onSessionReady?.({
|
|
1352
1372
|
activeSessionId: this.activeSessionId,
|
|
1353
1373
|
ws: this.opts.ws,
|
|
@@ -1361,7 +1381,7 @@ export class ParallAgentGateway {
|
|
|
1361
1381
|
const expectedMs = intervalSec * 1000;
|
|
1362
1382
|
const drift = now - this.lastHeartbeatAt - expectedMs;
|
|
1363
1383
|
if (drift > 15000) {
|
|
1364
|
-
log?.warn(`
|
|
1384
|
+
log?.warn(`heartbeat drift ${drift}ms — event loop may be blocked`);
|
|
1365
1385
|
}
|
|
1366
1386
|
this.lastHeartbeatAt = now;
|
|
1367
1387
|
if (this.opts.ws.state !== "connected")
|
|
@@ -1377,11 +1397,11 @@ export class ParallAgentGateway {
|
|
|
1377
1397
|
const isFirstHello = !this.hadSuccessfulHello;
|
|
1378
1398
|
this.hadSuccessfulHello = true;
|
|
1379
1399
|
this.catchUpFromDispatch(isFirstHello).catch((err) => {
|
|
1380
|
-
log?.warn(`
|
|
1400
|
+
log?.warn(`dispatch catch-up failed: ${String(err)}`);
|
|
1381
1401
|
});
|
|
1382
1402
|
}
|
|
1383
1403
|
catch (err) {
|
|
1384
|
-
log?.error(`
|
|
1404
|
+
log?.error(`failed to fetch chats: ${String(err)}`);
|
|
1385
1405
|
}
|
|
1386
1406
|
}
|
|
1387
1407
|
// Resolves when in-flight dispatches hit 0 or the deadline elapses.
|
|
@@ -1414,13 +1434,13 @@ export class ParallAgentGateway {
|
|
|
1414
1434
|
// the process exit — that's acceptable because K8s will retry the event
|
|
1415
1435
|
// via dispatch catch-up after the new pod starts.
|
|
1416
1436
|
if (this.inFlightDispatches > 0) {
|
|
1417
|
-
this.opts.log?.info(`
|
|
1437
|
+
this.opts.log?.info(`draining ${this.inFlightDispatches} in-flight dispatch(es), deadline ${this.SHUTDOWN_DEADLINE_MS}ms`);
|
|
1418
1438
|
await this.waitForDrain(this.SHUTDOWN_DEADLINE_MS);
|
|
1419
1439
|
if (this.inFlightDispatches > 0) {
|
|
1420
|
-
this.opts.log?.warn(`
|
|
1440
|
+
this.opts.log?.warn(`drain deadline hit; ${this.inFlightDispatches} dispatch(es) still running — they will be killed by process exit`);
|
|
1421
1441
|
}
|
|
1422
1442
|
else {
|
|
1423
|
-
this.opts.log?.info(`
|
|
1443
|
+
this.opts.log?.info(`drain complete`);
|
|
1424
1444
|
}
|
|
1425
1445
|
}
|
|
1426
1446
|
if (this.heartbeatTimer)
|
|
@@ -1431,6 +1451,6 @@ export class ParallAgentGateway {
|
|
|
1431
1451
|
this.activeDispatches.clear();
|
|
1432
1452
|
await this.opts.onBeforeDisconnect?.();
|
|
1433
1453
|
this.opts.ws.disconnect();
|
|
1434
|
-
this.opts.log?.info(`
|
|
1454
|
+
this.opts.log?.info(`disconnected`);
|
|
1435
1455
|
}
|
|
1436
1456
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export * from "./event-format.js";
|
|
|
5
5
|
export * from "./prompt-fragments.js";
|
|
6
6
|
export * from "./bridge-workspace.js";
|
|
7
7
|
export * from "./dispatch-adapter.js";
|
|
8
|
-
export { createLogger } from "./logger.js";
|
|
8
|
+
export { createLogger, childLogger } from "./logger.js";
|
|
9
9
|
export * from "./gateway-base.js";
|
|
10
10
|
export * from "./platform-config.js";
|
|
11
11
|
export { writeSkillFiles, buildSkillReferences, SKILLS } from "./skills/index.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACxD,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAClF,YAAY,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ export * from "./event-format.js";
|
|
|
5
5
|
export * from "./prompt-fragments.js";
|
|
6
6
|
export * from "./bridge-workspace.js";
|
|
7
7
|
export * from "./dispatch-adapter.js";
|
|
8
|
-
export { createLogger } from "./logger.js";
|
|
8
|
+
export { createLogger, childLogger } from "./logger.js";
|
|
9
9
|
export * from "./gateway-base.js";
|
|
10
10
|
export * from "./platform-config.js";
|
|
11
11
|
export { writeSkillFiles, buildSkillReferences, SKILLS } from "./skills/index.js";
|
package/dist/logger.d.ts
CHANGED
package/dist/logger.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAO1D;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,aAAa,CAE7E"}
|
package/dist/logger.js
CHANGED
|
@@ -3,5 +3,9 @@ export function createLogger(prefix) {
|
|
|
3
3
|
info: (msg) => console.log(`${new Date().toISOString()} [${prefix}] ${msg}`),
|
|
4
4
|
warn: (msg) => console.warn(`${new Date().toISOString()} [${prefix}] ${msg}`),
|
|
5
5
|
error: (msg) => console.error(`${new Date().toISOString()} [${prefix}] ${msg}`),
|
|
6
|
+
child: (sub) => createLogger(`${prefix}:${sub}`),
|
|
6
7
|
};
|
|
7
8
|
}
|
|
9
|
+
export function childLogger(logger, sub) {
|
|
10
|
+
return logger.child ? logger.child(sub) : logger;
|
|
11
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parall/agent-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.30.0",
|
|
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
|
+
"@parall/sdk": "1.30.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@types/node": "^22.0.0",
|
package/src/dispatch-adapter.ts
CHANGED
package/src/gateway-base.ts
CHANGED
|
@@ -4,6 +4,7 @@ import * as path from "node:path";
|
|
|
4
4
|
import { MENTION_ALL_USER_ID, ParallClient, ParallWs } from "@parall/sdk";
|
|
5
5
|
import type {
|
|
6
6
|
AgentConfigUpdateData,
|
|
7
|
+
AgentNewSessionData,
|
|
7
8
|
AgentSessionDB,
|
|
8
9
|
Approval,
|
|
9
10
|
Chat,
|
|
@@ -107,6 +108,7 @@ export type ParallGatewayOptions = {
|
|
|
107
108
|
onSessionReady?: (state: { activeSessionId?: string; ws: ParallWs; runtimeKey: string }) => Promise<void> | void;
|
|
108
109
|
onSessionBinding?: (state: { sessionKey: string; agentSessionId: string; runtimeSessionId: string; runtimeLaneKey: string }) => Promise<void> | void;
|
|
109
110
|
onBeforeDisconnect?: () => Promise<void> | void;
|
|
111
|
+
onNewSession?: (previousSessionId: string) => Promise<void> | void;
|
|
110
112
|
};
|
|
111
113
|
|
|
112
114
|
type AgentSessionBinding = {
|
|
@@ -196,6 +198,7 @@ export class ParallAgentGateway {
|
|
|
196
198
|
private shuttingDown = false;
|
|
197
199
|
private inFlightDispatches = 0;
|
|
198
200
|
private drainResolvers: Array<() => void> = [];
|
|
201
|
+
private pendingRestartNotification: string | null = null;
|
|
199
202
|
|
|
200
203
|
private readonly DISPATCHED_MESSAGES_CAP = 5000;
|
|
201
204
|
private readonly COLD_START_WINDOW_MS: number;
|
|
@@ -213,7 +216,7 @@ export class ParallAgentGateway {
|
|
|
213
216
|
const { ws, log } = this.opts;
|
|
214
217
|
|
|
215
218
|
ws.onStateChange((state) => {
|
|
216
|
-
log?.info(`
|
|
219
|
+
log?.info(`connection state → ${state}`);
|
|
217
220
|
});
|
|
218
221
|
|
|
219
222
|
ws.on("hello", async (data: HelloData) => {
|
|
@@ -249,18 +252,33 @@ export class ParallAgentGateway {
|
|
|
249
252
|
});
|
|
250
253
|
|
|
251
254
|
ws.on("agent_config.update", async (data: AgentConfigUpdateData) => {
|
|
252
|
-
this.opts.log?.info(`
|
|
255
|
+
this.opts.log?.info(`config update notification (version=${data.version})`);
|
|
253
256
|
try {
|
|
254
257
|
await this.opts.onConfigUpdate?.(data);
|
|
255
258
|
} catch (err) {
|
|
256
|
-
this.opts.log?.warn(`
|
|
259
|
+
this.opts.log?.warn(`config update failed: ${String(err)}`);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
ws.on("agent.new_session", async (data: AgentNewSessionData) => {
|
|
264
|
+
const prevId = data.previous_session_id ?? "";
|
|
265
|
+
this.opts.log?.info(`new session signal received (previous=${prevId})`);
|
|
266
|
+
this.sessionBindings.clear();
|
|
267
|
+
if (prevId) {
|
|
268
|
+
this.pendingRestartNotification =
|
|
269
|
+
`[Harness Notification] This is a fresh session. Your previous session (${prevId}) was ended by the user and you have been restarted.`;
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
await this.opts.onNewSession?.(prevId);
|
|
273
|
+
} catch (err) {
|
|
274
|
+
this.opts.log?.warn(`onNewSession callback failed: ${String(err)}`);
|
|
257
275
|
}
|
|
258
276
|
});
|
|
259
277
|
|
|
260
278
|
ws.on("recovery.overflow", () => {
|
|
261
|
-
this.opts.log?.warn(`
|
|
279
|
+
this.opts.log?.warn(`recovery.overflow — triggering full catch-up`);
|
|
262
280
|
this.catchUpFromDispatch().catch((err) =>
|
|
263
|
-
this.opts.log?.warn(`
|
|
281
|
+
this.opts.log?.warn(`overflow catch-up failed: ${String(err)}`));
|
|
264
282
|
});
|
|
265
283
|
|
|
266
284
|
ws.on("task.assigned", async (data: TaskAssignedData) => {
|
|
@@ -272,7 +290,7 @@ export class ParallAgentGateway {
|
|
|
272
290
|
this.opts.client.ackDispatch(this.opts.config.org_id, { source_type: "task_activity", source_id: data.id }).catch(() => {});
|
|
273
291
|
}
|
|
274
292
|
} catch (err) {
|
|
275
|
-
this.opts.log?.error(`
|
|
293
|
+
this.opts.log?.error(`task dispatch failed for ${data.id}: ${String(err)}`);
|
|
276
294
|
}
|
|
277
295
|
});
|
|
278
296
|
|
|
@@ -285,7 +303,7 @@ export class ParallAgentGateway {
|
|
|
285
303
|
this.opts.client.ackDispatchByID(this.opts.config.org_id, data.id).catch(() => {});
|
|
286
304
|
}
|
|
287
305
|
} catch (err) {
|
|
288
|
-
this.opts.log?.error(`
|
|
306
|
+
this.opts.log?.error(`task comment dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
289
307
|
}
|
|
290
308
|
} else if (data.event_type === "task_update") {
|
|
291
309
|
if (!data.task_id) return;
|
|
@@ -295,7 +313,7 @@ export class ParallAgentGateway {
|
|
|
295
313
|
this.opts.client.ackDispatchByID(this.opts.config.org_id, data.id).catch(() => {});
|
|
296
314
|
}
|
|
297
315
|
} catch (err) {
|
|
298
|
-
this.opts.log?.error(`
|
|
316
|
+
this.opts.log?.error(`task update dispatch failed for ${data.task_id}: ${String(err)}`);
|
|
299
317
|
}
|
|
300
318
|
} else if (data.event_type === "schedule.fire") {
|
|
301
319
|
if (!data.source_id) return;
|
|
@@ -305,7 +323,7 @@ export class ParallAgentGateway {
|
|
|
305
323
|
this.opts.client.ackDispatchByID(this.opts.config.org_id, data.id).catch(() => {});
|
|
306
324
|
}
|
|
307
325
|
} catch (err) {
|
|
308
|
-
this.opts.log?.error(`
|
|
326
|
+
this.opts.log?.error(`schedule fire dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
309
327
|
}
|
|
310
328
|
} else if (data.event_type === "approval_decided") {
|
|
311
329
|
if (!data.source_id) return;
|
|
@@ -315,7 +333,7 @@ export class ParallAgentGateway {
|
|
|
315
333
|
this.opts.client.ackDispatchByID(this.opts.config.org_id, data.id).catch(() => {});
|
|
316
334
|
}
|
|
317
335
|
} catch (err) {
|
|
318
|
-
this.opts.log?.error(`
|
|
336
|
+
this.opts.log?.error(`approval decided dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
319
337
|
}
|
|
320
338
|
} else if (data.event_type !== "message" && data.event_type !== "task_assign") {
|
|
321
339
|
// Truly unknown event_type — log so a newly-added dispatch type
|
|
@@ -325,11 +343,11 @@ export class ParallAgentGateway {
|
|
|
325
343
|
// (message.new, task.assigned) above and would otherwise spam
|
|
326
344
|
// info-level logs for every inbound chat message / task
|
|
327
345
|
// assignment on a busy agent.
|
|
328
|
-
this.opts.log?.info(`
|
|
346
|
+
this.opts.log?.info(`dispatch.new with unhandled event_type=${String(data.event_type)} (id=${data.id}) — no-op`);
|
|
329
347
|
}
|
|
330
348
|
});
|
|
331
349
|
|
|
332
|
-
this.opts.log?.info(`
|
|
350
|
+
this.opts.log?.info(`connecting to ${this.opts.connectionLabel ?? "Parall WS"}...`);
|
|
333
351
|
await ws.connect();
|
|
334
352
|
|
|
335
353
|
return new Promise<void>((resolve) => {
|
|
@@ -462,7 +480,7 @@ export class ParallAgentGateway {
|
|
|
462
480
|
},
|
|
463
481
|
});
|
|
464
482
|
} catch (err) {
|
|
465
|
-
this.opts.log?.warn(`
|
|
483
|
+
this.opts.log?.warn(`failed to create input step: ${String(err)}`);
|
|
466
484
|
}
|
|
467
485
|
}
|
|
468
486
|
|
|
@@ -546,12 +564,12 @@ export class ParallAgentGateway {
|
|
|
546
564
|
target_type: target.target_type,
|
|
547
565
|
target_id: target.target_id,
|
|
548
566
|
content: { text: runtimeEvent.message, suppressed: false },
|
|
549
|
-
projection:
|
|
567
|
+
projection: false,
|
|
550
568
|
});
|
|
551
569
|
break;
|
|
552
570
|
}
|
|
553
571
|
} catch (err) {
|
|
554
|
-
this.opts.log?.warn(`
|
|
572
|
+
this.opts.log?.warn(`failed to create ${runtimeEvent.type} step: ${String(err)}`);
|
|
555
573
|
}
|
|
556
574
|
}
|
|
557
575
|
|
|
@@ -560,7 +578,7 @@ export class ParallAgentGateway {
|
|
|
560
578
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
561
579
|
fs.writeFileSync(filePath, JSON.stringify(ctx), "utf8");
|
|
562
580
|
} catch (err) {
|
|
563
|
-
this.opts.log?.warn(`
|
|
581
|
+
this.opts.log?.warn(`failed to write context file ${filePath}: ${String(err)}`);
|
|
564
582
|
}
|
|
565
583
|
}
|
|
566
584
|
|
|
@@ -571,7 +589,7 @@ export class ParallAgentGateway {
|
|
|
571
589
|
ctx.step_id = stepId;
|
|
572
590
|
fs.writeFileSync(filePath, JSON.stringify(ctx), "utf8");
|
|
573
591
|
} catch (err) {
|
|
574
|
-
this.opts.log?.warn(`
|
|
592
|
+
this.opts.log?.warn(`failed to update context file step_id ${filePath}: ${String(err)}`);
|
|
575
593
|
}
|
|
576
594
|
}
|
|
577
595
|
|
|
@@ -582,7 +600,7 @@ export class ParallAgentGateway {
|
|
|
582
600
|
ctx.session_id = sessionId;
|
|
583
601
|
fs.writeFileSync(filePath, JSON.stringify(ctx), "utf8");
|
|
584
602
|
} catch (err) {
|
|
585
|
-
this.opts.log?.warn(`
|
|
603
|
+
this.opts.log?.warn(`failed to update context file session_id ${filePath}: ${String(err)}`);
|
|
586
604
|
}
|
|
587
605
|
}
|
|
588
606
|
|
|
@@ -592,7 +610,7 @@ export class ParallAgentGateway {
|
|
|
592
610
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
593
611
|
fs.writeFileSync(filePath, stepId, "utf8");
|
|
594
612
|
} catch (err) {
|
|
595
|
-
this.opts.log?.warn(`
|
|
613
|
+
this.opts.log?.warn(`failed to write step id file ${filePath}: ${String(err)}`);
|
|
596
614
|
}
|
|
597
615
|
}
|
|
598
616
|
|
|
@@ -675,11 +693,16 @@ export class ParallAgentGateway {
|
|
|
675
693
|
// and are awaited by shutdown() up to SHUTDOWN_DEADLINE_MS.
|
|
676
694
|
if (this.shuttingDown) {
|
|
677
695
|
this.opts.log?.info(
|
|
678
|
-
`
|
|
696
|
+
`skipping dispatch for ${event.messageId} (shutting down) — leaving unacked for catch-up on replacement pod`,
|
|
679
697
|
);
|
|
680
698
|
return false;
|
|
681
699
|
}
|
|
682
700
|
|
|
701
|
+
if (this.pendingRestartNotification) {
|
|
702
|
+
bodyForAgent = this.pendingRestartNotification + "\n\n---\n\n" + bodyForAgent;
|
|
703
|
+
this.pendingRestartNotification = null;
|
|
704
|
+
}
|
|
705
|
+
|
|
683
706
|
setSessionChatId(sessionKey, event.targetId);
|
|
684
707
|
setSessionMessageId(sessionKey, event.messageId);
|
|
685
708
|
setDispatchMessageId(sessionKey, event.messageId);
|
|
@@ -832,7 +855,7 @@ export class ParallAgentGateway {
|
|
|
832
855
|
item.resolve(true);
|
|
833
856
|
}
|
|
834
857
|
} catch (err) {
|
|
835
|
-
this.opts.log?.error(`
|
|
858
|
+
this.opts.log?.error(`fork dispatch failed for ${last.messageId}: ${String(err)}`);
|
|
836
859
|
for (const item of items) {
|
|
837
860
|
item.resolve(false);
|
|
838
861
|
}
|
|
@@ -851,7 +874,7 @@ export class ParallAgentGateway {
|
|
|
851
874
|
try {
|
|
852
875
|
historyPath = this.opts.dispatchAdapter.getSessionHistoryPath?.(fork.fork.sessionKey);
|
|
853
876
|
} catch (err) {
|
|
854
|
-
this.opts.log?.warn?.(`
|
|
877
|
+
this.opts.log?.warn?.(`failed to resolve fork history path: ${String(err)}`);
|
|
855
878
|
}
|
|
856
879
|
this.dispatchState.pendingForkResults.push({
|
|
857
880
|
forkSessionKey: fork.fork.sessionKey,
|
|
@@ -911,7 +934,7 @@ export class ParallAgentGateway {
|
|
|
911
934
|
// pod is the single source of truth for replay.
|
|
912
935
|
if (this.shuttingDown) {
|
|
913
936
|
this.opts.log?.info(
|
|
914
|
-
`
|
|
937
|
+
`drainMainBuffer halted (shutting down) — ${this.dispatchState.mainBuffer.length} buffered, ${this.dispatchState.pendingForkResults.length} pending fork results left for catch-up`,
|
|
915
938
|
);
|
|
916
939
|
break;
|
|
917
940
|
}
|
|
@@ -1006,7 +1029,7 @@ export class ParallAgentGateway {
|
|
|
1006
1029
|
) {
|
|
1007
1030
|
this.startInjectedTyping(event);
|
|
1008
1031
|
this.opts.log?.info(
|
|
1009
|
-
`
|
|
1032
|
+
`steer injected for ${event.messageId} (will drain for bookkeeping)`,
|
|
1010
1033
|
);
|
|
1011
1034
|
}
|
|
1012
1035
|
// If the main dispatch cycle ended while we awaited the steer RPC,
|
|
@@ -1043,7 +1066,7 @@ export class ParallAgentGateway {
|
|
|
1043
1066
|
});
|
|
1044
1067
|
|
|
1045
1068
|
if (!fork) {
|
|
1046
|
-
this.opts.log?.warn(`
|
|
1069
|
+
this.opts.log?.warn(`fork failed, buffering event for main session`);
|
|
1047
1070
|
this.dispatchState.mainBuffer.push(event);
|
|
1048
1071
|
return false;
|
|
1049
1072
|
}
|
|
@@ -1061,7 +1084,7 @@ export class ParallAgentGateway {
|
|
|
1061
1084
|
activeFork.queue.push({ event, resolve });
|
|
1062
1085
|
});
|
|
1063
1086
|
this.runForkDrainLoop(activeFork).catch((err) => {
|
|
1064
|
-
this.opts.log?.error(`
|
|
1087
|
+
this.opts.log?.error(`fork drain loop error: ${String(err)}`);
|
|
1065
1088
|
});
|
|
1066
1089
|
return firstEventPromise;
|
|
1067
1090
|
}
|
|
@@ -1081,7 +1104,7 @@ export class ParallAgentGateway {
|
|
|
1081
1104
|
this.chatInfoMap.set(chatId, chatInfo);
|
|
1082
1105
|
return chatInfo;
|
|
1083
1106
|
} catch (err) {
|
|
1084
|
-
this.opts.log?.warn(`
|
|
1107
|
+
this.opts.log?.warn(`failed to resolve chat ${chatId}: ${String(err)}`);
|
|
1085
1108
|
return null;
|
|
1086
1109
|
}
|
|
1087
1110
|
}
|
|
@@ -1161,7 +1184,7 @@ export class ParallAgentGateway {
|
|
|
1161
1184
|
this.dispatchedMessages.delete(data.id);
|
|
1162
1185
|
}
|
|
1163
1186
|
} catch (err) {
|
|
1164
|
-
this.opts.log?.error(`
|
|
1187
|
+
this.opts.log?.error(`event dispatch failed for ${data.id}: ${String(err)}`);
|
|
1165
1188
|
this.dispatchedMessages.delete(data.id);
|
|
1166
1189
|
}
|
|
1167
1190
|
}
|
|
@@ -1170,11 +1193,11 @@ export class ParallAgentGateway {
|
|
|
1170
1193
|
if (this.shuttingDown) return false; // drain window — let server requeue via catch-up
|
|
1171
1194
|
const dedupeKey = `${task.id}:${task.updated_at}`;
|
|
1172
1195
|
if (this.dispatchedTasks.has(dedupeKey)) {
|
|
1173
|
-
this.opts.log?.info(`
|
|
1196
|
+
this.opts.log?.info(`skipping already-dispatched task ${task.identifier ?? task.id}`);
|
|
1174
1197
|
return false;
|
|
1175
1198
|
}
|
|
1176
1199
|
this.dispatchedTasks.add(dedupeKey);
|
|
1177
|
-
this.opts.log?.info(`
|
|
1200
|
+
this.opts.log?.info(`task assigned: ${task.identifier ?? task.id} "${task.title}"`);
|
|
1178
1201
|
|
|
1179
1202
|
const parts = [`Title: ${task.title}`];
|
|
1180
1203
|
parts.push(`Status: ${task.status}`, `Priority: ${task.priority}`);
|
|
@@ -1220,7 +1243,7 @@ export class ParallAgentGateway {
|
|
|
1220
1243
|
const isCreatorUpdate = opts.allowCreator === true && task.creator_id === this.opts.agentUserId;
|
|
1221
1244
|
if (!isAssignee && !isCreatorUpdate) {
|
|
1222
1245
|
this.opts.log?.info(
|
|
1223
|
-
`
|
|
1246
|
+
`skipping stale task dispatch ${ackSourceId ?? taskId} — assigned to ${task.assignee_id}, creator ${task.creator_id}`,
|
|
1224
1247
|
);
|
|
1225
1248
|
return true;
|
|
1226
1249
|
}
|
|
@@ -1245,7 +1268,7 @@ export class ParallAgentGateway {
|
|
|
1245
1268
|
const status = (err as { status?: number })?.status;
|
|
1246
1269
|
if (status === 404) {
|
|
1247
1270
|
// Comment deleted — ack stale dispatch so it doesn't pile up.
|
|
1248
|
-
this.opts.log?.info(`
|
|
1271
|
+
this.opts.log?.info(`skipping deleted comment ${commentId}, acking stale dispatch`);
|
|
1249
1272
|
this.dispatchedTasks.delete(dedupeKey);
|
|
1250
1273
|
return true; // caller will ack
|
|
1251
1274
|
}
|
|
@@ -1257,7 +1280,7 @@ export class ParallAgentGateway {
|
|
|
1257
1280
|
return true; // null response = gone, ack stale dispatch
|
|
1258
1281
|
}
|
|
1259
1282
|
if (comment.hints?.no_reply) {
|
|
1260
|
-
this.opts.log?.info(`
|
|
1283
|
+
this.opts.log?.info(`skipping no_reply task comment ${commentId}, acking stale dispatch`);
|
|
1261
1284
|
this.dispatchedTasks.delete(dedupeKey);
|
|
1262
1285
|
return true;
|
|
1263
1286
|
}
|
|
@@ -1268,7 +1291,7 @@ export class ParallAgentGateway {
|
|
|
1268
1291
|
} catch { /* task context is optional */ }
|
|
1269
1292
|
|
|
1270
1293
|
const taskLabel = task ? `${task.identifier ?? task.id} "${task.title}"` : taskId;
|
|
1271
|
-
this.opts.log?.info(`
|
|
1294
|
+
this.opts.log?.info(`task comment on ${taskLabel} by ${actorId ?? "unknown"}`);
|
|
1272
1295
|
|
|
1273
1296
|
const parts: string[] = [];
|
|
1274
1297
|
if (task) {
|
|
@@ -1328,10 +1351,10 @@ export class ParallAgentGateway {
|
|
|
1328
1351
|
// already-delivered run — this is expected but operationally
|
|
1329
1352
|
// visible, so warn (not info) keeps it findable during incident
|
|
1330
1353
|
// triage. See docs/primitives/schedule.md § Snapshot 不变性.
|
|
1331
|
-
this.opts.log?.warn(`
|
|
1354
|
+
this.opts.log?.warn(`schedule run ${runId} not accessible (404), acking stale dispatch`);
|
|
1332
1355
|
return true;
|
|
1333
1356
|
}
|
|
1334
|
-
this.opts.log?.warn(`
|
|
1357
|
+
this.opts.log?.warn(`schedule run fetch failed for ${runId}, leaving pending: ${String(err)}`);
|
|
1335
1358
|
return false;
|
|
1336
1359
|
}
|
|
1337
1360
|
if (!run) return true;
|
|
@@ -1343,7 +1366,7 @@ export class ParallAgentGateway {
|
|
|
1343
1366
|
const dedupeKey = `schedule_run:${run.id}`;
|
|
1344
1367
|
if (this.dispatchedTasks.has(dedupeKey)) return false;
|
|
1345
1368
|
this.dispatchedTasks.add(dedupeKey);
|
|
1346
|
-
this.opts.log?.info(`
|
|
1369
|
+
this.opts.log?.info(`schedule fired: ${run.id} (schedule ${run.schedule_id})`);
|
|
1347
1370
|
|
|
1348
1371
|
const event: ParallEvent = {
|
|
1349
1372
|
type: "schedule",
|
|
@@ -1383,10 +1406,10 @@ export class ParallAgentGateway {
|
|
|
1383
1406
|
} catch (err: unknown) {
|
|
1384
1407
|
const status = (err as { status?: number })?.status;
|
|
1385
1408
|
if (status === 404 || status === 403) {
|
|
1386
|
-
this.opts.log?.warn(`
|
|
1409
|
+
this.opts.log?.warn(`approval ${approvalId} not accessible (${status}), acking stale dispatch`);
|
|
1387
1410
|
return true;
|
|
1388
1411
|
}
|
|
1389
|
-
this.opts.log?.warn(`
|
|
1412
|
+
this.opts.log?.warn(`approval fetch failed for ${approvalId}, leaving pending: ${String(err)}`);
|
|
1390
1413
|
return false;
|
|
1391
1414
|
}
|
|
1392
1415
|
if (!approval) return true;
|
|
@@ -1395,7 +1418,7 @@ export class ParallAgentGateway {
|
|
|
1395
1418
|
const dedupeKey = `approval:${approval.id}`;
|
|
1396
1419
|
if (this.dispatchedTasks.has(dedupeKey)) return false;
|
|
1397
1420
|
this.dispatchedTasks.add(dedupeKey);
|
|
1398
|
-
this.opts.log?.info(`
|
|
1421
|
+
this.opts.log?.info(`approval decided: ${approval.id} (${approval.status})`);
|
|
1399
1422
|
|
|
1400
1423
|
const statusLabel = approval.status === "approved" ? "Approved" : "Rejected";
|
|
1401
1424
|
const execInfo = approval.execution_status ? ` | execution: ${approval.execution_status}` : "";
|
|
@@ -1452,14 +1475,14 @@ export class ParallAgentGateway {
|
|
|
1452
1475
|
try {
|
|
1453
1476
|
dispatched = await this.handleTaskDispatch(item.task_id, item.source_id ?? item.task_id);
|
|
1454
1477
|
} catch (err: unknown) {
|
|
1455
|
-
this.opts.log?.warn(`
|
|
1478
|
+
this.opts.log?.warn(`catch-up task fetch failed for ${item.task_id}, leaving pending: ${String(err)}`);
|
|
1456
1479
|
continue;
|
|
1457
1480
|
}
|
|
1458
1481
|
} else if (item.event_type === "task_update" && item.task_id) {
|
|
1459
1482
|
try {
|
|
1460
1483
|
dispatched = await this.handleTaskDispatch(item.task_id, item.source_id ?? item.task_id, { allowCreator: true });
|
|
1461
1484
|
} catch (err: unknown) {
|
|
1462
|
-
this.opts.log?.warn(`
|
|
1485
|
+
this.opts.log?.warn(`catch-up task fetch failed for ${item.task_id}, leaving pending: ${String(err)}`);
|
|
1463
1486
|
continue;
|
|
1464
1487
|
}
|
|
1465
1488
|
} else if (item.event_type === "task_comment" && item.source_id && item.task_id) {
|
|
@@ -1480,7 +1503,7 @@ export class ParallAgentGateway {
|
|
|
1480
1503
|
msg = null;
|
|
1481
1504
|
} else {
|
|
1482
1505
|
msgFetchFailed = true;
|
|
1483
|
-
this.opts.log?.warn(`
|
|
1506
|
+
this.opts.log?.warn(`catch-up message fetch failed for ${item.source_id}, leaving pending: ${String(err)}`);
|
|
1484
1507
|
}
|
|
1485
1508
|
}
|
|
1486
1509
|
if (msgFetchFailed) {
|
|
@@ -1510,7 +1533,7 @@ export class ParallAgentGateway {
|
|
|
1510
1533
|
this.opts.client.ackDispatchByID(this.opts.config.org_id, item.id).catch(() => {});
|
|
1511
1534
|
}
|
|
1512
1535
|
} catch (err) {
|
|
1513
|
-
this.opts.log?.warn(`
|
|
1536
|
+
this.opts.log?.warn(`catch-up dispatch ${item.id} (${item.event_type}) failed: ${String(err)}`);
|
|
1514
1537
|
}
|
|
1515
1538
|
}
|
|
1516
1539
|
// Stop paginating once shutdown begins — the inner loop already broke,
|
|
@@ -1519,7 +1542,7 @@ export class ParallAgentGateway {
|
|
|
1519
1542
|
} while (cursor);
|
|
1520
1543
|
|
|
1521
1544
|
if (processed > 0 || skippedOld > 0) {
|
|
1522
|
-
this.opts.log?.info(`
|
|
1545
|
+
this.opts.log?.info(`dispatch catch-up: processed ${processed}, skipped ${skippedOld} old item(s)`);
|
|
1523
1546
|
}
|
|
1524
1547
|
}
|
|
1525
1548
|
|
|
@@ -1529,7 +1552,7 @@ export class ParallAgentGateway {
|
|
|
1529
1552
|
const intervalSec = data.heartbeat_interval > 0 ? data.heartbeat_interval : 30;
|
|
1530
1553
|
try {
|
|
1531
1554
|
const count = await fetchAllChats(client, config.org_id, this.chatInfoMap);
|
|
1532
|
-
log?.info(`
|
|
1555
|
+
log?.info(`WebSocket connected, ${count} chats cached`);
|
|
1533
1556
|
|
|
1534
1557
|
await this.opts.onSessionReady?.({
|
|
1535
1558
|
activeSessionId: this.activeSessionId,
|
|
@@ -1544,7 +1567,7 @@ export class ParallAgentGateway {
|
|
|
1544
1567
|
const expectedMs = intervalSec * 1000;
|
|
1545
1568
|
const drift = now - this.lastHeartbeatAt - expectedMs;
|
|
1546
1569
|
if (drift > 15000) {
|
|
1547
|
-
log?.warn(`
|
|
1570
|
+
log?.warn(`heartbeat drift ${drift}ms — event loop may be blocked`);
|
|
1548
1571
|
}
|
|
1549
1572
|
this.lastHeartbeatAt = now;
|
|
1550
1573
|
if (this.opts.ws.state !== "connected") return;
|
|
@@ -1560,10 +1583,10 @@ export class ParallAgentGateway {
|
|
|
1560
1583
|
const isFirstHello = !this.hadSuccessfulHello;
|
|
1561
1584
|
this.hadSuccessfulHello = true;
|
|
1562
1585
|
this.catchUpFromDispatch(isFirstHello).catch((err) => {
|
|
1563
|
-
log?.warn(`
|
|
1586
|
+
log?.warn(`dispatch catch-up failed: ${String(err)}`);
|
|
1564
1587
|
});
|
|
1565
1588
|
} catch (err) {
|
|
1566
|
-
log?.error(`
|
|
1589
|
+
log?.error(`failed to fetch chats: ${String(err)}`);
|
|
1567
1590
|
}
|
|
1568
1591
|
}
|
|
1569
1592
|
|
|
@@ -1598,15 +1621,15 @@ export class ParallAgentGateway {
|
|
|
1598
1621
|
// via dispatch catch-up after the new pod starts.
|
|
1599
1622
|
if (this.inFlightDispatches > 0) {
|
|
1600
1623
|
this.opts.log?.info(
|
|
1601
|
-
`
|
|
1624
|
+
`draining ${this.inFlightDispatches} in-flight dispatch(es), deadline ${this.SHUTDOWN_DEADLINE_MS}ms`,
|
|
1602
1625
|
);
|
|
1603
1626
|
await this.waitForDrain(this.SHUTDOWN_DEADLINE_MS);
|
|
1604
1627
|
if (this.inFlightDispatches > 0) {
|
|
1605
1628
|
this.opts.log?.warn(
|
|
1606
|
-
`
|
|
1629
|
+
`drain deadline hit; ${this.inFlightDispatches} dispatch(es) still running — they will be killed by process exit`,
|
|
1607
1630
|
);
|
|
1608
1631
|
} else {
|
|
1609
|
-
this.opts.log?.info(`
|
|
1632
|
+
this.opts.log?.info(`drain complete`);
|
|
1610
1633
|
}
|
|
1611
1634
|
}
|
|
1612
1635
|
|
|
@@ -1619,6 +1642,6 @@ export class ParallAgentGateway {
|
|
|
1619
1642
|
await this.opts.onBeforeDisconnect?.();
|
|
1620
1643
|
|
|
1621
1644
|
this.opts.ws.disconnect();
|
|
1622
|
-
this.opts.log?.info(`
|
|
1645
|
+
this.opts.log?.info(`disconnected`);
|
|
1623
1646
|
}
|
|
1624
1647
|
}
|
package/src/index.ts
CHANGED
|
@@ -5,7 +5,7 @@ export * from "./event-format.js";
|
|
|
5
5
|
export * from "./prompt-fragments.js";
|
|
6
6
|
export * from "./bridge-workspace.js";
|
|
7
7
|
export * from "./dispatch-adapter.js";
|
|
8
|
-
export { createLogger } from "./logger.js";
|
|
8
|
+
export { createLogger, childLogger } from "./logger.js";
|
|
9
9
|
export * from "./gateway-base.js";
|
|
10
10
|
export * from "./platform-config.js";
|
|
11
11
|
export { writeSkillFiles, buildSkillReferences, SKILLS } from "./skills/index.js";
|
package/src/logger.ts
CHANGED
|
@@ -5,5 +5,10 @@ export function createLogger(prefix: string): GatewayLogger {
|
|
|
5
5
|
info: (msg: string) => console.log(`${new Date().toISOString()} [${prefix}] ${msg}`),
|
|
6
6
|
warn: (msg: string) => console.warn(`${new Date().toISOString()} [${prefix}] ${msg}`),
|
|
7
7
|
error: (msg: string) => console.error(`${new Date().toISOString()} [${prefix}] ${msg}`),
|
|
8
|
+
child: (sub: string) => createLogger(`${prefix}:${sub}`),
|
|
8
9
|
};
|
|
9
10
|
}
|
|
11
|
+
|
|
12
|
+
export function childLogger(logger: GatewayLogger, sub: string): GatewayLogger {
|
|
13
|
+
return logger.child ? logger.child(sub) : logger;
|
|
14
|
+
}
|