@parall/agent-core 1.32.1 → 1.34.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/gateway-base.d.ts +2 -0
- package/dist/gateway-base.d.ts.map +1 -1
- package/dist/gateway-base.js +79 -2
- package/package.json +2 -2
- package/src/gateway-base.ts +100 -2
package/dist/gateway-base.d.ts
CHANGED
|
@@ -106,6 +106,8 @@ export declare class ParallAgentGateway {
|
|
|
106
106
|
private handleScheduleFire;
|
|
107
107
|
private fetchAndHandleApprovalDecided;
|
|
108
108
|
private catchUpFromDispatch;
|
|
109
|
+
private buildOfflineSummary;
|
|
110
|
+
private formatAge;
|
|
109
111
|
private handleHello;
|
|
110
112
|
private waitForDrain;
|
|
111
113
|
private shutdown;
|
|
@@ -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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"}
|
package/dist/gateway-base.js
CHANGED
|
@@ -1610,8 +1610,29 @@ export class ParallAgentGateway {
|
|
|
1610
1610
|
return dispatched;
|
|
1611
1611
|
}
|
|
1612
1612
|
async catchUpFromDispatch() {
|
|
1613
|
+
const OVERFLOW_THRESHOLD = 500;
|
|
1614
|
+
const EXPIRE_AGE_HOURS = 24;
|
|
1615
|
+
const CATCHUP_MAX = 10;
|
|
1616
|
+
let expireSummary = null;
|
|
1617
|
+
let overflowMode = false;
|
|
1618
|
+
try {
|
|
1619
|
+
const { count } = await this.opts.client.getDispatchPendingCount(this.opts.config.org_id);
|
|
1620
|
+
if (count > OVERFLOW_THRESHOLD) {
|
|
1621
|
+
overflowMode = true;
|
|
1622
|
+
const result = await this.opts.client.expireDispatch(this.opts.config.org_id, EXPIRE_AGE_HOURS);
|
|
1623
|
+
if (result.total > 0) {
|
|
1624
|
+
this.opts.log?.warn(`dispatch catch-up overflow: ${count} pending, expired ${result.total} events older than ${EXPIRE_AGE_HOURS}h`);
|
|
1625
|
+
expireSummary = this.buildOfflineSummary(result.groups);
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
catch (err) {
|
|
1630
|
+
this.opts.log?.warn(`dispatch catch-up overflow check failed: ${String(err)}`);
|
|
1631
|
+
}
|
|
1613
1632
|
let cursor;
|
|
1614
1633
|
let processed = 0;
|
|
1634
|
+
let skipped = 0;
|
|
1635
|
+
const skippedByType = new Map();
|
|
1615
1636
|
do {
|
|
1616
1637
|
const page = await this.opts.client.getDispatch(this.opts.config.org_id, {
|
|
1617
1638
|
limit: 50,
|
|
@@ -1622,6 +1643,18 @@ export class ParallAgentGateway {
|
|
|
1622
1643
|
// will only reject. Items remain unacked for the replacement pod.
|
|
1623
1644
|
if (this.shuttingDown)
|
|
1624
1645
|
break;
|
|
1646
|
+
if (overflowMode && processed >= CATCHUP_MAX) {
|
|
1647
|
+
try {
|
|
1648
|
+
await this.opts.client.ackDispatchByID(this.opts.config.org_id, item.id);
|
|
1649
|
+
skipped++;
|
|
1650
|
+
const key = item.event_type;
|
|
1651
|
+
skippedByType.set(key, (skippedByType.get(key) ?? 0) + 1);
|
|
1652
|
+
}
|
|
1653
|
+
catch {
|
|
1654
|
+
this.opts.log?.warn(`catch-up skip ack failed for ${item.id}, leaving pending`);
|
|
1655
|
+
}
|
|
1656
|
+
continue;
|
|
1657
|
+
}
|
|
1625
1658
|
processed++;
|
|
1626
1659
|
try {
|
|
1627
1660
|
let dispatched = false;
|
|
@@ -1706,10 +1739,54 @@ export class ParallAgentGateway {
|
|
|
1706
1739
|
// and the next page would be wasted API work the replacement pod redoes.
|
|
1707
1740
|
cursor = !this.shuttingDown && page.has_more ? page.next_cursor : undefined;
|
|
1708
1741
|
} while (cursor);
|
|
1709
|
-
if (
|
|
1710
|
-
|
|
1742
|
+
if (expireSummary || skipped > 0) {
|
|
1743
|
+
const parts = [];
|
|
1744
|
+
if (expireSummary)
|
|
1745
|
+
parts.push(expireSummary);
|
|
1746
|
+
if (skipped > 0) {
|
|
1747
|
+
const recentLines = [...skippedByType.entries()]
|
|
1748
|
+
.map(([type, count]) => `- ${count} recent ${type.replace('.', ' ').replace('_', ' ')} events`)
|
|
1749
|
+
.join('\n');
|
|
1750
|
+
parts.push(expireSummary
|
|
1751
|
+
? `Additionally, ${skipped} recent events exceeded the catch-up limit and were skipped:\n${recentLines}`
|
|
1752
|
+
: `[Offline Summary] You were offline. ${skipped} pending events exceeded the catch-up limit and were skipped:\n${recentLines}\n\nUse your tools (read messages, check tasks) to review anything still relevant.`);
|
|
1753
|
+
}
|
|
1754
|
+
const fullSummary = parts.join('\n\n');
|
|
1755
|
+
this.pendingRestartNotification = this.pendingRestartNotification
|
|
1756
|
+
? `${this.pendingRestartNotification}\n\n${fullSummary}`
|
|
1757
|
+
: fullSummary;
|
|
1758
|
+
}
|
|
1759
|
+
if (processed > 0 || skipped > 0) {
|
|
1760
|
+
this.opts.log?.info(`dispatch catch-up: processed ${processed}, skipped ${skipped}`);
|
|
1711
1761
|
}
|
|
1712
1762
|
}
|
|
1763
|
+
buildOfflineSummary(groups) {
|
|
1764
|
+
const lines = [
|
|
1765
|
+
'[Offline Summary] You were offline and had a large backlog of pending events. The following old events were skipped:',
|
|
1766
|
+
];
|
|
1767
|
+
for (const g of groups) {
|
|
1768
|
+
const age = this.formatAge(g.oldest);
|
|
1769
|
+
if (g.chat_id && g.event_type === 'message') {
|
|
1770
|
+
const name = g.chat_name ?? g.chat_id;
|
|
1771
|
+
lines.push(`- ${g.count} messages in "${name}" (oldest: ${age})`);
|
|
1772
|
+
}
|
|
1773
|
+
else {
|
|
1774
|
+
const label = g.event_type.replace('.', ' ').replace('_', ' ');
|
|
1775
|
+
lines.push(`- ${g.count} ${label} events (oldest: ${age})`);
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
lines.push('');
|
|
1779
|
+
lines.push('These events were too old to process individually. Use your tools (read messages, check tasks) to review anything still relevant.');
|
|
1780
|
+
return lines.join('\n');
|
|
1781
|
+
}
|
|
1782
|
+
formatAge(iso) {
|
|
1783
|
+
const ms = Date.now() - new Date(iso).getTime();
|
|
1784
|
+
const hours = Math.floor(ms / 3_600_000);
|
|
1785
|
+
if (hours < 24)
|
|
1786
|
+
return `${hours}h ago`;
|
|
1787
|
+
const days = Math.floor(hours / 24);
|
|
1788
|
+
return `${days}d ago`;
|
|
1789
|
+
}
|
|
1713
1790
|
async handleHello(data) {
|
|
1714
1791
|
const { client, config, log } = this.opts;
|
|
1715
1792
|
this.sessionId = data.session_id ?? '';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parall/agent-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.34.0",
|
|
4
4
|
"description": "Shared agent runtime orchestration helpers for Parall",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"@opentelemetry/sdk-logs": "^0.57.0",
|
|
36
36
|
"@opentelemetry/sdk-metrics": "^1.30.0",
|
|
37
37
|
"@opentelemetry/sdk-trace-node": "^1.30.0",
|
|
38
|
-
"@parall/sdk": "1.
|
|
38
|
+
"@parall/sdk": "1.34.0"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@types/node": "^22.0.0",
|
package/src/gateway-base.ts
CHANGED
|
@@ -1979,8 +1979,34 @@ export class ParallAgentGateway {
|
|
|
1979
1979
|
}
|
|
1980
1980
|
|
|
1981
1981
|
private async catchUpFromDispatch() {
|
|
1982
|
+
const OVERFLOW_THRESHOLD = 500;
|
|
1983
|
+
const EXPIRE_AGE_HOURS = 24;
|
|
1984
|
+
const CATCHUP_MAX = 10;
|
|
1985
|
+
let expireSummary: string | null = null;
|
|
1986
|
+
let overflowMode = false;
|
|
1987
|
+
|
|
1988
|
+
try {
|
|
1989
|
+
const { count } = await this.opts.client.getDispatchPendingCount(this.opts.config.org_id);
|
|
1990
|
+
if (count > OVERFLOW_THRESHOLD) {
|
|
1991
|
+
overflowMode = true;
|
|
1992
|
+
const result = await this.opts.client.expireDispatch(
|
|
1993
|
+
this.opts.config.org_id,
|
|
1994
|
+
EXPIRE_AGE_HOURS,
|
|
1995
|
+
);
|
|
1996
|
+
if (result.total > 0) {
|
|
1997
|
+
this.opts.log?.warn(
|
|
1998
|
+
`dispatch catch-up overflow: ${count} pending, expired ${result.total} events older than ${EXPIRE_AGE_HOURS}h`,
|
|
1999
|
+
);
|
|
2000
|
+
expireSummary = this.buildOfflineSummary(result.groups);
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
} catch (err) {
|
|
2004
|
+
this.opts.log?.warn(`dispatch catch-up overflow check failed: ${String(err)}`);
|
|
2005
|
+
}
|
|
1982
2006
|
let cursor: string | undefined;
|
|
1983
2007
|
let processed = 0;
|
|
2008
|
+
let skipped = 0;
|
|
2009
|
+
const skippedByType = new Map<string, number>();
|
|
1984
2010
|
|
|
1985
2011
|
do {
|
|
1986
2012
|
const page = await this.opts.client.getDispatch(this.opts.config.org_id, {
|
|
@@ -1993,6 +2019,18 @@ export class ParallAgentGateway {
|
|
|
1993
2019
|
// will only reject. Items remain unacked for the replacement pod.
|
|
1994
2020
|
if (this.shuttingDown) break;
|
|
1995
2021
|
|
|
2022
|
+
if (overflowMode && processed >= CATCHUP_MAX) {
|
|
2023
|
+
try {
|
|
2024
|
+
await this.opts.client.ackDispatchByID(this.opts.config.org_id, item.id);
|
|
2025
|
+
skipped++;
|
|
2026
|
+
const key = item.event_type;
|
|
2027
|
+
skippedByType.set(key, (skippedByType.get(key) ?? 0) + 1);
|
|
2028
|
+
} catch {
|
|
2029
|
+
this.opts.log?.warn(`catch-up skip ack failed for ${item.id}, leaving pending`);
|
|
2030
|
+
}
|
|
2031
|
+
continue;
|
|
2032
|
+
}
|
|
2033
|
+
|
|
1996
2034
|
processed++;
|
|
1997
2035
|
try {
|
|
1998
2036
|
let dispatched = false;
|
|
@@ -2096,9 +2134,69 @@ export class ParallAgentGateway {
|
|
|
2096
2134
|
cursor = !this.shuttingDown && page.has_more ? page.next_cursor : undefined;
|
|
2097
2135
|
} while (cursor);
|
|
2098
2136
|
|
|
2099
|
-
if (
|
|
2100
|
-
|
|
2137
|
+
if (expireSummary || skipped > 0) {
|
|
2138
|
+
const parts: string[] = [];
|
|
2139
|
+
if (expireSummary) parts.push(expireSummary);
|
|
2140
|
+
if (skipped > 0) {
|
|
2141
|
+
const recentLines = [...skippedByType.entries()]
|
|
2142
|
+
.map(
|
|
2143
|
+
([type, count]) =>
|
|
2144
|
+
`- ${count} recent ${type.replace('.', ' ').replace('_', ' ')} events`,
|
|
2145
|
+
)
|
|
2146
|
+
.join('\n');
|
|
2147
|
+
parts.push(
|
|
2148
|
+
expireSummary
|
|
2149
|
+
? `Additionally, ${skipped} recent events exceeded the catch-up limit and were skipped:\n${recentLines}`
|
|
2150
|
+
: `[Offline Summary] You were offline. ${skipped} pending events exceeded the catch-up limit and were skipped:\n${recentLines}\n\nUse your tools (read messages, check tasks) to review anything still relevant.`,
|
|
2151
|
+
);
|
|
2152
|
+
}
|
|
2153
|
+
const fullSummary = parts.join('\n\n');
|
|
2154
|
+
this.pendingRestartNotification = this.pendingRestartNotification
|
|
2155
|
+
? `${this.pendingRestartNotification}\n\n${fullSummary}`
|
|
2156
|
+
: fullSummary;
|
|
2101
2157
|
}
|
|
2158
|
+
|
|
2159
|
+
if (processed > 0 || skipped > 0) {
|
|
2160
|
+
this.opts.log?.info(`dispatch catch-up: processed ${processed}, skipped ${skipped}`);
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
|
|
2164
|
+
private buildOfflineSummary(
|
|
2165
|
+
groups: Array<{
|
|
2166
|
+
chat_id: string | null;
|
|
2167
|
+
chat_name?: string | null;
|
|
2168
|
+
event_type: string;
|
|
2169
|
+
count: number;
|
|
2170
|
+
oldest: string;
|
|
2171
|
+
newest: string;
|
|
2172
|
+
}>,
|
|
2173
|
+
): string {
|
|
2174
|
+
const lines: string[] = [
|
|
2175
|
+
'[Offline Summary] You were offline and had a large backlog of pending events. The following old events were skipped:',
|
|
2176
|
+
];
|
|
2177
|
+
for (const g of groups) {
|
|
2178
|
+
const age = this.formatAge(g.oldest);
|
|
2179
|
+
if (g.chat_id && g.event_type === 'message') {
|
|
2180
|
+
const name = g.chat_name ?? g.chat_id;
|
|
2181
|
+
lines.push(`- ${g.count} messages in "${name}" (oldest: ${age})`);
|
|
2182
|
+
} else {
|
|
2183
|
+
const label = g.event_type.replace('.', ' ').replace('_', ' ');
|
|
2184
|
+
lines.push(`- ${g.count} ${label} events (oldest: ${age})`);
|
|
2185
|
+
}
|
|
2186
|
+
}
|
|
2187
|
+
lines.push('');
|
|
2188
|
+
lines.push(
|
|
2189
|
+
'These events were too old to process individually. Use your tools (read messages, check tasks) to review anything still relevant.',
|
|
2190
|
+
);
|
|
2191
|
+
return lines.join('\n');
|
|
2192
|
+
}
|
|
2193
|
+
|
|
2194
|
+
private formatAge(iso: string): string {
|
|
2195
|
+
const ms = Date.now() - new Date(iso).getTime();
|
|
2196
|
+
const hours = Math.floor(ms / 3_600_000);
|
|
2197
|
+
if (hours < 24) return `${hours}h ago`;
|
|
2198
|
+
const days = Math.floor(hours / 24);
|
|
2199
|
+
return `${days}d ago`;
|
|
2102
2200
|
}
|
|
2103
2201
|
|
|
2104
2202
|
private async handleHello(data: HelloData) {
|