ework-daemon 0.4.71 → 0.4.72
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/package.json +1 -1
- package/src/opencode.ts +26 -2
package/package.json
CHANGED
package/src/opencode.ts
CHANGED
|
@@ -422,6 +422,13 @@ export class Engine {
|
|
|
422
422
|
private static MAX_INLINE_SIZE = 4000;
|
|
423
423
|
private static MAX_NUDGE_ROUNDS = 1;
|
|
424
424
|
private static MAX_EMPTY_RESPONSE_ROUNDS = 1;
|
|
425
|
+
// A queued (pending) message older than this is dead context — e.g. forwards
|
|
426
|
+
// left over from a webhook echo storm, or comments queued behind a session
|
|
427
|
+
// that ran for hours. Replaying them re-runs stale prompts and ping-pongs
|
|
428
|
+
// nudges ("reply → done → drain next stale → nudge → reply …"), observed on
|
|
429
|
+
// dog/tasks#3: 17:24 storm forwards replayed at 20:09–20:11. Expire instead
|
|
430
|
+
// of replay; explicit retryMessage bypasses this via { force: true }.
|
|
431
|
+
private static MAX_PENDING_AGE_MS = 30 * 60_000;
|
|
425
432
|
private static MAX_STUCK_NUDGE_ROUNDS = 1;
|
|
426
433
|
private static MAX_RUNTIME_MS = 3 * 60 * 60 * 1000;
|
|
427
434
|
private static OBSERVER_INTERVAL_MS = 5 * 60 * 1000;
|
|
@@ -1717,7 +1724,24 @@ export class Engine {
|
|
|
1717
1724
|
}
|
|
1718
1725
|
}
|
|
1719
1726
|
|
|
1720
|
-
private async dequeueOrIdle(k: string, session: OpSession, issue: Issue, msg: Message) {
|
|
1727
|
+
private async dequeueOrIdle(k: string, session: OpSession, issue: Issue, msg: Message, opts: { force?: boolean } = {}) {
|
|
1728
|
+
if (!opts.force) {
|
|
1729
|
+
let next: Message | undefined = msg;
|
|
1730
|
+
while (next) {
|
|
1731
|
+
const age = Date.now() - next.createdAt.getTime();
|
|
1732
|
+
if (age <= Engine.MAX_PENDING_AGE_MS) break;
|
|
1733
|
+
log.warn(`engine: expiring stale pending msg ${next.id.slice(0, 8)} for ${k} (age ${Math.round(age / 60_000)}min > ${Math.round(Engine.MAX_PENDING_AGE_MS / 60_000)}min) — skipping replay`);
|
|
1734
|
+
await this.store.updateMessageStatus(next.id, "failed", "expired: stale pending message not replayed");
|
|
1735
|
+
next = await this.store.getNextPendingMessage(session.id);
|
|
1736
|
+
}
|
|
1737
|
+
if (!next) {
|
|
1738
|
+
this.clearRuntimeState(k);
|
|
1739
|
+
await this.store.updateSession(session.id, { state: "idle" });
|
|
1740
|
+
void this.drainGlobalPending();
|
|
1741
|
+
return;
|
|
1742
|
+
}
|
|
1743
|
+
msg = next;
|
|
1744
|
+
}
|
|
1721
1745
|
log.info(`engine: running dequeued msg ${msg.id.slice(0, 8)} for ${k}`);
|
|
1722
1746
|
await this.store.updateMessageStatus(msg.id, "running");
|
|
1723
1747
|
this.running.add(k);
|
|
@@ -2238,7 +2262,7 @@ export class Engine {
|
|
|
2238
2262
|
await this.store.updateMessageStatus(messageId, "pending");
|
|
2239
2263
|
const k = this.sessionKey(session, issue);
|
|
2240
2264
|
if (!this.running.has(k)) {
|
|
2241
|
-
await this.dequeueOrIdle(k, session, issue, msg);
|
|
2265
|
+
await this.dequeueOrIdle(k, session, issue, msg, { force: true });
|
|
2242
2266
|
}
|
|
2243
2267
|
return true;
|
|
2244
2268
|
}
|