@cydm/pie 1.0.15 → 1.0.16
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/builtin/extensions/ask-user/index.js +1 -1
- package/dist/builtin/extensions/plan-mode/index.js +1 -1
- package/dist/builtin/extensions/subagent/index.js +2 -2
- package/dist/builtin/extensions/todo/index.js +1 -1
- package/dist/chunks/{chunk-55RUSXEA.js → chunk-62XU6P2H.js} +1 -1
- package/dist/chunks/{chunk-R5LYKDKA.js → chunk-7GAYJ6AF.js} +680 -94
- package/dist/cli.js +398 -140
- package/package.json +2 -2
|
@@ -1471,36 +1471,66 @@ var DEFAULT_COMPACTION_CONFIG = {
|
|
|
1471
1471
|
compactPrompt: COMPACT_PROMPT,
|
|
1472
1472
|
summaryPrefix: SUMMARY_PREFIX
|
|
1473
1473
|
};
|
|
1474
|
+
var APPROX_BYTES_PER_TOKEN = 4;
|
|
1475
|
+
var RESIZED_IMAGE_BYTES_ESTIMATE = 7373;
|
|
1474
1476
|
function estimateTokens(message) {
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
return Math.ceil(chars / 4);
|
|
1477
|
+
return approximateBytesAsTokens(estimateModelVisibleBytes(message));
|
|
1478
|
+
}
|
|
1479
|
+
function calculateTotalTokens(messages) {
|
|
1480
|
+
return messages.reduce((sum, m) => sum + estimateTokens(m), 0);
|
|
1481
|
+
}
|
|
1482
|
+
function calculateContextTokens(usage) {
|
|
1483
|
+
return usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite;
|
|
1484
|
+
}
|
|
1485
|
+
function getAssistantUsage(message) {
|
|
1486
|
+
if (message.role !== "assistant") {
|
|
1487
|
+
return void 0;
|
|
1487
1488
|
}
|
|
1488
|
-
if (message.
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1489
|
+
if (message.stopReason === "aborted" || message.stopReason === "error") {
|
|
1490
|
+
return void 0;
|
|
1491
|
+
}
|
|
1492
|
+
if (calculateContextTokens(message.usage) <= 0) {
|
|
1493
|
+
return void 0;
|
|
1494
|
+
}
|
|
1495
|
+
return message.usage;
|
|
1496
|
+
}
|
|
1497
|
+
function estimateContextTokens(messages) {
|
|
1498
|
+
const localTokens = calculateTotalTokens(messages);
|
|
1499
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1500
|
+
const usage = getAssistantUsage(messages[i]);
|
|
1501
|
+
if (!usage) {
|
|
1502
|
+
continue;
|
|
1496
1503
|
}
|
|
1497
|
-
|
|
1504
|
+
const providerTokens = calculateContextTokens(usage);
|
|
1505
|
+
const trailingTokens = calculateTotalTokens(messages.slice(i + 1));
|
|
1506
|
+
const usageTokens = providerTokens;
|
|
1507
|
+
return {
|
|
1508
|
+
tokens: Math.max(providerTokens + trailingTokens, localTokens),
|
|
1509
|
+
usageTokens,
|
|
1510
|
+
providerTokens,
|
|
1511
|
+
localTokens,
|
|
1512
|
+
trailingTokens,
|
|
1513
|
+
lastUsageIndex: i
|
|
1514
|
+
};
|
|
1498
1515
|
}
|
|
1499
|
-
|
|
1500
|
-
|
|
1516
|
+
return {
|
|
1517
|
+
tokens: localTokens,
|
|
1518
|
+
usageTokens: 0,
|
|
1519
|
+
providerTokens: 0,
|
|
1520
|
+
localTokens,
|
|
1521
|
+
trailingTokens: localTokens,
|
|
1522
|
+
lastUsageIndex: null
|
|
1523
|
+
};
|
|
1501
1524
|
}
|
|
1502
|
-
function
|
|
1503
|
-
|
|
1525
|
+
function getAutoCompactTokenLimit(contextWindow, reserveTokens, autoCompactTokenLimit) {
|
|
1526
|
+
const explicitLimit = autoCompactTokenLimit !== void 0 && autoCompactTokenLimit > 0 ? Math.floor(autoCompactTokenLimit) : void 0;
|
|
1527
|
+
if (!contextWindow || contextWindow <= 0) {
|
|
1528
|
+
return explicitLimit;
|
|
1529
|
+
}
|
|
1530
|
+
const reserveLimit = reserveTokens >= contextWindow ? Math.floor(contextWindow * 0.8) : contextWindow - reserveTokens;
|
|
1531
|
+
const windowLimit = Math.floor(contextWindow * 0.9);
|
|
1532
|
+
const defaultLimit = Math.max(1, Math.min(reserveLimit, windowLimit));
|
|
1533
|
+
return explicitLimit !== void 0 ? Math.min(defaultLimit, explicitLimit) : defaultLimit;
|
|
1504
1534
|
}
|
|
1505
1535
|
function isCompactSummaryMessage(message, summaryPrefix = SUMMARY_PREFIX) {
|
|
1506
1536
|
return message.startsWith(`${summaryPrefix}
|
|
@@ -1692,6 +1722,138 @@ function appendFileOperationsToSummary(summary, messages) {
|
|
|
1692
1722
|
const { readFiles, modifiedFiles } = computeFileLists(fileOps);
|
|
1693
1723
|
return `${summary}${formatFileOperations(readFiles, modifiedFiles)}`;
|
|
1694
1724
|
}
|
|
1725
|
+
function estimateModelVisibleBytes(message) {
|
|
1726
|
+
const visibleMessage = normalizeModelVisibleMessage(message);
|
|
1727
|
+
const wrapperBytes = utf8ByteLength(safeStringify(visibleMessage));
|
|
1728
|
+
return wrapperBytes + estimateMessageMediaBytes(message);
|
|
1729
|
+
}
|
|
1730
|
+
function normalizeModelVisibleMessage(message) {
|
|
1731
|
+
if (message.role === "user") {
|
|
1732
|
+
return {
|
|
1733
|
+
role: "user",
|
|
1734
|
+
content: typeof message.content === "string" ? message.content : message.content.map(normalizeUserContentBlock)
|
|
1735
|
+
};
|
|
1736
|
+
}
|
|
1737
|
+
if (message.role === "assistant") {
|
|
1738
|
+
return {
|
|
1739
|
+
role: "assistant",
|
|
1740
|
+
content: message.content.map((block) => {
|
|
1741
|
+
if (block.type === "text") {
|
|
1742
|
+
return {
|
|
1743
|
+
type: "text",
|
|
1744
|
+
text: block.text,
|
|
1745
|
+
...block.textSignature ? { textSignature: block.textSignature } : {}
|
|
1746
|
+
};
|
|
1747
|
+
}
|
|
1748
|
+
if (block.type === "thinking") {
|
|
1749
|
+
return {
|
|
1750
|
+
type: "thinking",
|
|
1751
|
+
thinking: block.thinking,
|
|
1752
|
+
...block.thinkingSignature ? { thinkingSignature: block.thinkingSignature } : {}
|
|
1753
|
+
};
|
|
1754
|
+
}
|
|
1755
|
+
if (block.type === "toolCall") {
|
|
1756
|
+
return {
|
|
1757
|
+
type: "toolCall",
|
|
1758
|
+
id: block.id,
|
|
1759
|
+
name: block.name,
|
|
1760
|
+
arguments: block.arguments ?? {},
|
|
1761
|
+
...block.thoughtSignature ? { thoughtSignature: block.thoughtSignature } : {}
|
|
1762
|
+
};
|
|
1763
|
+
}
|
|
1764
|
+
return block;
|
|
1765
|
+
})
|
|
1766
|
+
};
|
|
1767
|
+
}
|
|
1768
|
+
if (message.role === "toolResult") {
|
|
1769
|
+
return {
|
|
1770
|
+
role: "toolResult",
|
|
1771
|
+
toolCallId: message.toolCallId,
|
|
1772
|
+
toolName: message.toolName,
|
|
1773
|
+
isError: message.isError,
|
|
1774
|
+
content: message.content.map(normalizeUserContentBlock)
|
|
1775
|
+
};
|
|
1776
|
+
}
|
|
1777
|
+
return {
|
|
1778
|
+
role: String(message.role ?? "unknown"),
|
|
1779
|
+
content: getMessageText(message)
|
|
1780
|
+
};
|
|
1781
|
+
}
|
|
1782
|
+
function normalizeUserContentBlock(block) {
|
|
1783
|
+
if (block.type === "text") {
|
|
1784
|
+
return { type: "text", text: block.text };
|
|
1785
|
+
}
|
|
1786
|
+
if (block.type === "image") {
|
|
1787
|
+
return { type: "image", mimeType: block.mimeType };
|
|
1788
|
+
}
|
|
1789
|
+
if (block.type === "audio") {
|
|
1790
|
+
return { type: "audio", mimeType: block.mimeType };
|
|
1791
|
+
}
|
|
1792
|
+
if (block.type === "video") {
|
|
1793
|
+
return { type: "video", mimeType: block.mimeType };
|
|
1794
|
+
}
|
|
1795
|
+
if (block.type === "fileRef") {
|
|
1796
|
+
return {
|
|
1797
|
+
type: "fileRef",
|
|
1798
|
+
url: block.url,
|
|
1799
|
+
mimeType: block.mimeType,
|
|
1800
|
+
modality: block.modality
|
|
1801
|
+
};
|
|
1802
|
+
}
|
|
1803
|
+
return block;
|
|
1804
|
+
}
|
|
1805
|
+
function estimateMessageMediaBytes(message) {
|
|
1806
|
+
if (message.role === "user" && Array.isArray(message.content)) {
|
|
1807
|
+
return message.content.reduce((sum, block) => sum + estimateUserContentBlockMediaBytes(block), 0);
|
|
1808
|
+
}
|
|
1809
|
+
if (message.role === "toolResult") {
|
|
1810
|
+
return message.content.reduce((sum, block) => sum + estimateUserContentBlockMediaBytes(block), 0);
|
|
1811
|
+
}
|
|
1812
|
+
return 0;
|
|
1813
|
+
}
|
|
1814
|
+
function estimateUserContentBlockMediaBytes(block) {
|
|
1815
|
+
if (block.type === "image") {
|
|
1816
|
+
return estimateImageContentBytes(block);
|
|
1817
|
+
}
|
|
1818
|
+
if (block.type === "audio") {
|
|
1819
|
+
return estimateInlineDataBytes(block);
|
|
1820
|
+
}
|
|
1821
|
+
if (block.type === "video") {
|
|
1822
|
+
return estimateInlineDataBytes(block);
|
|
1823
|
+
}
|
|
1824
|
+
return 0;
|
|
1825
|
+
}
|
|
1826
|
+
function estimateImageContentBytes(block) {
|
|
1827
|
+
return Math.max(RESIZED_IMAGE_BYTES_ESTIMATE, estimateInlineDataBytes(block));
|
|
1828
|
+
}
|
|
1829
|
+
function estimateInlineDataBytes(block) {
|
|
1830
|
+
return utf8ByteLength(block.data || "");
|
|
1831
|
+
}
|
|
1832
|
+
function approximateBytesAsTokens(bytes) {
|
|
1833
|
+
return Math.ceil(bytes / APPROX_BYTES_PER_TOKEN);
|
|
1834
|
+
}
|
|
1835
|
+
function safeStringify(value) {
|
|
1836
|
+
try {
|
|
1837
|
+
return JSON.stringify(value) ?? "";
|
|
1838
|
+
} catch {
|
|
1839
|
+
return String(value ?? "");
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
var utf8Encoder = typeof globalThis.TextEncoder === "function" ? new globalThis.TextEncoder() : void 0;
|
|
1843
|
+
function utf8ByteLength(text) {
|
|
1844
|
+
if (utf8Encoder) {
|
|
1845
|
+
return utf8Encoder.encode(text).length;
|
|
1846
|
+
}
|
|
1847
|
+
let bytes = 0;
|
|
1848
|
+
for (const char of text) {
|
|
1849
|
+
const codePoint = char.codePointAt(0) ?? 0;
|
|
1850
|
+
if (codePoint <= 127) bytes += 1;
|
|
1851
|
+
else if (codePoint <= 2047) bytes += 2;
|
|
1852
|
+
else if (codePoint <= 65535) bytes += 3;
|
|
1853
|
+
else bytes += 4;
|
|
1854
|
+
}
|
|
1855
|
+
return bytes;
|
|
1856
|
+
}
|
|
1695
1857
|
function isSyntheticUserEnvelope(text) {
|
|
1696
1858
|
const trimmed = text.trimStart();
|
|
1697
1859
|
return trimmed.startsWith("<environment_context>") || trimmed.startsWith("<turn_aborted>") || trimmed.startsWith("# AGENTS.md instructions") || trimmed.startsWith("## Project Context\nProject-specific instructions from AGENTS.md");
|
|
@@ -2807,13 +2969,20 @@ var AgentSessionAutoCompactScheduler = class {
|
|
|
2807
2969
|
options;
|
|
2808
2970
|
autoCompactTimer;
|
|
2809
2971
|
pendingAutoCompact;
|
|
2972
|
+
runningAutoCompact;
|
|
2973
|
+
pendingWait;
|
|
2974
|
+
resolvePendingWait;
|
|
2810
2975
|
get hasPendingAutoCompact() {
|
|
2811
|
-
return this.autoCompactTimer !== void 0;
|
|
2976
|
+
return this.autoCompactTimer !== void 0 || this.pendingAutoCompact !== void 0 || this.runningAutoCompact !== void 0;
|
|
2977
|
+
}
|
|
2978
|
+
waitForAutoCompact() {
|
|
2979
|
+
return this.pendingWait ?? Promise.resolve();
|
|
2812
2980
|
}
|
|
2813
2981
|
schedule(decision, delayMs = 0) {
|
|
2814
2982
|
if (this.options.getRuntimeGuardTriggered()) {
|
|
2815
2983
|
return;
|
|
2816
2984
|
}
|
|
2985
|
+
this.ensurePendingWait();
|
|
2817
2986
|
this.pendingAutoCompact = decision;
|
|
2818
2987
|
if (this.autoCompactTimer !== void 0) {
|
|
2819
2988
|
return;
|
|
@@ -2824,6 +2993,7 @@ var AgentSessionAutoCompactScheduler = class {
|
|
|
2824
2993
|
const pending = this.pendingAutoCompact;
|
|
2825
2994
|
this.pendingAutoCompact = void 0;
|
|
2826
2995
|
if (!pending || this.options.getDisposed()) {
|
|
2996
|
+
this.resolvePending();
|
|
2827
2997
|
return;
|
|
2828
2998
|
}
|
|
2829
2999
|
if (this.options.isStreaming()) {
|
|
@@ -2831,17 +3001,33 @@ var AgentSessionAutoCompactScheduler = class {
|
|
|
2831
3001
|
this.schedule(pending, 100);
|
|
2832
3002
|
return;
|
|
2833
3003
|
}
|
|
2834
|
-
|
|
3004
|
+
this.runningAutoCompact = this.options.runAutoCompact(pending).catch(() => {
|
|
3005
|
+
}).finally(() => {
|
|
3006
|
+
this.runningAutoCompact = void 0;
|
|
3007
|
+
this.resolvePending();
|
|
3008
|
+
});
|
|
2835
3009
|
}, delayMs);
|
|
2836
3010
|
}
|
|
2837
3011
|
cancel() {
|
|
2838
|
-
if (this.autoCompactTimer
|
|
2839
|
-
|
|
3012
|
+
if (this.autoCompactTimer !== void 0) {
|
|
3013
|
+
const clearTimer = this.options.retry?.clearTimeout ?? defaultClearTimeout;
|
|
3014
|
+
clearTimer(this.autoCompactTimer);
|
|
3015
|
+
this.autoCompactTimer = void 0;
|
|
2840
3016
|
}
|
|
2841
|
-
const clearTimer = this.options.retry?.clearTimeout ?? defaultClearTimeout;
|
|
2842
|
-
clearTimer(this.autoCompactTimer);
|
|
2843
|
-
this.autoCompactTimer = void 0;
|
|
2844
3017
|
this.pendingAutoCompact = void 0;
|
|
3018
|
+
this.resolvePending();
|
|
3019
|
+
}
|
|
3020
|
+
ensurePendingWait() {
|
|
3021
|
+
if (this.pendingWait) return;
|
|
3022
|
+
this.pendingWait = new Promise((resolve2) => {
|
|
3023
|
+
this.resolvePendingWait = resolve2;
|
|
3024
|
+
});
|
|
3025
|
+
}
|
|
3026
|
+
resolvePending() {
|
|
3027
|
+
const resolve2 = this.resolvePendingWait;
|
|
3028
|
+
this.pendingWait = void 0;
|
|
3029
|
+
this.resolvePendingWait = void 0;
|
|
3030
|
+
resolve2?.();
|
|
2845
3031
|
}
|
|
2846
3032
|
};
|
|
2847
3033
|
|
|
@@ -2858,15 +3044,24 @@ var AgentSessionAutoContinueController = class {
|
|
|
2858
3044
|
}
|
|
2859
3045
|
options;
|
|
2860
3046
|
autoContinueTimer;
|
|
3047
|
+
pendingAutoContinue;
|
|
3048
|
+
resolvePendingAutoContinue;
|
|
3049
|
+
get hasPendingAutoContinue() {
|
|
3050
|
+
return this.autoContinueTimer !== void 0 || this.pendingAutoContinue !== void 0;
|
|
3051
|
+
}
|
|
3052
|
+
waitForAutoContinue() {
|
|
3053
|
+
return this.pendingAutoContinue ?? Promise.resolve();
|
|
3054
|
+
}
|
|
2861
3055
|
schedule(messages) {
|
|
2862
3056
|
if (!this.options.getAutoContinueMessage || this.options.getDisposed() || this.autoContinueTimer !== void 0) {
|
|
2863
3057
|
return;
|
|
2864
3058
|
}
|
|
3059
|
+
this.ensurePending();
|
|
2865
3060
|
const setTimer = this.options.retry?.setTimeout ?? defaultSetTimeout2;
|
|
2866
3061
|
const snapshot = messages.slice();
|
|
2867
3062
|
this.autoContinueTimer = setTimer(() => {
|
|
2868
3063
|
this.autoContinueTimer = void 0;
|
|
2869
|
-
void this.maybeScheduleAutoContinue(snapshot);
|
|
3064
|
+
void this.maybeScheduleAutoContinue(snapshot).finally(() => this.resolvePending());
|
|
2870
3065
|
}, 0);
|
|
2871
3066
|
}
|
|
2872
3067
|
cancel() {
|
|
@@ -2876,9 +3071,10 @@ var AgentSessionAutoContinueController = class {
|
|
|
2876
3071
|
const clearTimer = this.options.retry?.clearTimeout ?? defaultClearTimeout2;
|
|
2877
3072
|
clearTimer(this.autoContinueTimer);
|
|
2878
3073
|
this.autoContinueTimer = void 0;
|
|
3074
|
+
this.resolvePending();
|
|
2879
3075
|
}
|
|
2880
3076
|
async maybeScheduleAutoContinue(messages) {
|
|
2881
|
-
if (!this.options.getAutoContinueMessage || this.options.getDisposed() || this.options.getRuntimeGuardTriggered() || this.options.hasQueuedMessages() || this.options.isStreaming()) {
|
|
3077
|
+
if (!this.options.getAutoContinueMessage || this.options.getDisposed() || this.options.getRuntimeGuardTriggered() || this.options.isBlockedByRuntimePolicy() || this.options.hasQueuedMessages() || this.options.isStreaming()) {
|
|
2882
3078
|
if (this.options.hasQueuedMessages()) {
|
|
2883
3079
|
this.options.emit({ type: "auto_continue_skipped", reason: "queued_messages" });
|
|
2884
3080
|
}
|
|
@@ -2902,21 +3098,36 @@ var AgentSessionAutoContinueController = class {
|
|
|
2902
3098
|
this.options.emit({ type: "auto_continue_skipped", reason: reason ?? "no_message" });
|
|
2903
3099
|
return;
|
|
2904
3100
|
}
|
|
2905
|
-
if (this.options.hasQueuedMessages() || this.options.isStreaming()) {
|
|
3101
|
+
if (this.options.hasQueuedMessages() || this.options.isStreaming() || this.options.isBlockedByRuntimePolicy()) {
|
|
2906
3102
|
this.options.emit({ type: "auto_continue_skipped", reason: "runtime_busy" });
|
|
2907
3103
|
return;
|
|
2908
3104
|
}
|
|
2909
3105
|
this.options.emit({ type: "auto_continue_scheduled", reason });
|
|
2910
3106
|
this.options.agent.followUp(message);
|
|
2911
3107
|
const setTimer = this.options.retry?.setTimeout ?? defaultSetTimeout2;
|
|
2912
|
-
|
|
2913
|
-
this.autoContinueTimer =
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
3108
|
+
await new Promise((resolve2) => {
|
|
3109
|
+
this.autoContinueTimer = setTimer(() => {
|
|
3110
|
+
this.autoContinueTimer = void 0;
|
|
3111
|
+
if (this.options.getDisposed()) {
|
|
3112
|
+
resolve2();
|
|
3113
|
+
return;
|
|
3114
|
+
}
|
|
3115
|
+
void this.options.continueTurn().catch(() => {
|
|
3116
|
+
}).finally(resolve2);
|
|
3117
|
+
}, 0);
|
|
3118
|
+
});
|
|
3119
|
+
}
|
|
3120
|
+
ensurePending() {
|
|
3121
|
+
if (this.pendingAutoContinue) return;
|
|
3122
|
+
this.pendingAutoContinue = new Promise((resolve2) => {
|
|
3123
|
+
this.resolvePendingAutoContinue = resolve2;
|
|
3124
|
+
});
|
|
3125
|
+
}
|
|
3126
|
+
resolvePending() {
|
|
3127
|
+
const resolve2 = this.resolvePendingAutoContinue;
|
|
3128
|
+
this.pendingAutoContinue = void 0;
|
|
3129
|
+
this.resolvePendingAutoContinue = void 0;
|
|
3130
|
+
resolve2?.();
|
|
2920
3131
|
}
|
|
2921
3132
|
};
|
|
2922
3133
|
|
|
@@ -2934,7 +3145,7 @@ async function runAgentSessionCompaction(params) {
|
|
|
2934
3145
|
}
|
|
2935
3146
|
params.emit({ type: "auto_compaction_start", reason: params.reason, willRetry: params.willRetry });
|
|
2936
3147
|
try {
|
|
2937
|
-
if (params.
|
|
3148
|
+
if (params.willRetry) {
|
|
2938
3149
|
params.removeTrailingAssistantError();
|
|
2939
3150
|
}
|
|
2940
3151
|
const result = await params.compaction.compact({
|
|
@@ -3028,6 +3239,27 @@ async function preparePromptMessages(params) {
|
|
|
3028
3239
|
};
|
|
3029
3240
|
}
|
|
3030
3241
|
|
|
3242
|
+
// ../../packages/agent-framework/src/session/controller/pre-request-policy.ts
|
|
3243
|
+
async function runPreRequestAutoCompact(params) {
|
|
3244
|
+
if (params.disposed || params.runtimeGuardTriggered || params.isStreaming || params.recoveryActive || params.agent.state.messages.length === 0) {
|
|
3245
|
+
return;
|
|
3246
|
+
}
|
|
3247
|
+
const decision = params.getAutoCompactDecision?.({
|
|
3248
|
+
agent: params.agent,
|
|
3249
|
+
sessionManager: params.sessionManager,
|
|
3250
|
+
cwd: params.cwd,
|
|
3251
|
+
messages: params.agent.state.messages.slice()
|
|
3252
|
+
});
|
|
3253
|
+
if (decision?.reason !== "threshold") {
|
|
3254
|
+
return;
|
|
3255
|
+
}
|
|
3256
|
+
try {
|
|
3257
|
+
await params.runAutoCompact();
|
|
3258
|
+
} catch {
|
|
3259
|
+
params.setRecoveryState("none");
|
|
3260
|
+
}
|
|
3261
|
+
}
|
|
3262
|
+
|
|
3031
3263
|
// ../../packages/agent-framework/src/session/controller/queue.ts
|
|
3032
3264
|
function cloneQueuedInput(input) {
|
|
3033
3265
|
return {
|
|
@@ -3186,14 +3418,23 @@ var AgentSessionQueueDispatcher = class {
|
|
|
3186
3418
|
}
|
|
3187
3419
|
options;
|
|
3188
3420
|
dispatchTimer;
|
|
3421
|
+
pendingDispatch;
|
|
3422
|
+
resolvePendingDispatch;
|
|
3423
|
+
get hasPendingDispatch() {
|
|
3424
|
+
return this.dispatchTimer !== void 0 || this.pendingDispatch !== void 0;
|
|
3425
|
+
}
|
|
3426
|
+
waitForDispatch() {
|
|
3427
|
+
return this.pendingDispatch ?? Promise.resolve();
|
|
3428
|
+
}
|
|
3189
3429
|
schedule(delayMs = 0) {
|
|
3190
3430
|
if (this.options.getDisposed() || this.options.getRuntimeGuardTriggered() || this.dispatchTimer !== void 0) {
|
|
3191
3431
|
return;
|
|
3192
3432
|
}
|
|
3433
|
+
this.ensurePending();
|
|
3193
3434
|
const setTimer = this.options.retry?.setTimeout ?? defaultSetTimeout3;
|
|
3194
3435
|
this.dispatchTimer = setTimer(() => {
|
|
3195
3436
|
this.dispatchTimer = void 0;
|
|
3196
|
-
void this.dispatchNext();
|
|
3437
|
+
void this.dispatchNext().finally(() => this.resolvePending());
|
|
3197
3438
|
}, delayMs);
|
|
3198
3439
|
}
|
|
3199
3440
|
cancel() {
|
|
@@ -3203,6 +3444,7 @@ var AgentSessionQueueDispatcher = class {
|
|
|
3203
3444
|
const clearTimer = this.options.retry?.clearTimeout ?? defaultClearTimeout3;
|
|
3204
3445
|
clearTimer(this.dispatchTimer);
|
|
3205
3446
|
this.dispatchTimer = void 0;
|
|
3447
|
+
this.resolvePending();
|
|
3206
3448
|
}
|
|
3207
3449
|
async dispatchNext() {
|
|
3208
3450
|
if (this.options.getDisposed() || this.options.isStreaming() || this.options.isBlockedByRuntimePolicy()) {
|
|
@@ -3230,6 +3472,11 @@ var AgentSessionQueueDispatcher = class {
|
|
|
3230
3472
|
}
|
|
3231
3473
|
return false;
|
|
3232
3474
|
}
|
|
3475
|
+
await this.options.runPreRequestAutoCompact();
|
|
3476
|
+
if (this.options.getDisposed() || this.options.isStreaming() || this.options.isBlockedByRuntimePolicy()) {
|
|
3477
|
+
this.schedule(100);
|
|
3478
|
+
return false;
|
|
3479
|
+
}
|
|
3233
3480
|
const dispatched = this.options.queue.shift();
|
|
3234
3481
|
if (!dispatched) {
|
|
3235
3482
|
return false;
|
|
@@ -3259,8 +3506,56 @@ var AgentSessionQueueDispatcher = class {
|
|
|
3259
3506
|
}
|
|
3260
3507
|
return true;
|
|
3261
3508
|
}
|
|
3509
|
+
ensurePending() {
|
|
3510
|
+
if (this.pendingDispatch) return;
|
|
3511
|
+
this.pendingDispatch = new Promise((resolve2) => {
|
|
3512
|
+
this.resolvePendingDispatch = resolve2;
|
|
3513
|
+
});
|
|
3514
|
+
}
|
|
3515
|
+
resolvePending() {
|
|
3516
|
+
const resolve2 = this.resolvePendingDispatch;
|
|
3517
|
+
this.pendingDispatch = void 0;
|
|
3518
|
+
this.resolvePendingDispatch = void 0;
|
|
3519
|
+
resolve2?.();
|
|
3520
|
+
}
|
|
3262
3521
|
};
|
|
3263
3522
|
|
|
3523
|
+
// ../../packages/agent-framework/src/session/controller/failure-classification.ts
|
|
3524
|
+
function isAssistantFailureMessage(message) {
|
|
3525
|
+
return message?.role === "assistant" && (message.stopReason === "error" || message.stopReason === "aborted");
|
|
3526
|
+
}
|
|
3527
|
+
function isAssistantTerminalCompletion(message) {
|
|
3528
|
+
if (message?.role !== "assistant") return false;
|
|
3529
|
+
if (message.stopReason === "error" || message.stopReason === "aborted") return false;
|
|
3530
|
+
if (message.stopReason === "toolUse") return false;
|
|
3531
|
+
return !message.content.some((block) => block.type === "toolCall");
|
|
3532
|
+
}
|
|
3533
|
+
function createFailureClassification(context, retry, classifyFailure) {
|
|
3534
|
+
const hostClassification = classifyFailure?.(context);
|
|
3535
|
+
if (hostClassification) {
|
|
3536
|
+
return hostClassification;
|
|
3537
|
+
}
|
|
3538
|
+
const retryable = retry?.isRetryableError(context.errorMessage) === true;
|
|
3539
|
+
const userAbort = context.message?.role === "assistant" && context.message.stopReason === "aborted";
|
|
3540
|
+
return {
|
|
3541
|
+
kind: userAbort ? "user_abort" : retryable ? "provider_transient" : "unknown",
|
|
3542
|
+
retryable: retryable && !userAbort,
|
|
3543
|
+
compactable: false,
|
|
3544
|
+
userAbort,
|
|
3545
|
+
terminal: !retryable || userAbort,
|
|
3546
|
+
message: context.errorMessage
|
|
3547
|
+
};
|
|
3548
|
+
}
|
|
3549
|
+
function asTerminalFailure(failure, message = failure.message) {
|
|
3550
|
+
return {
|
|
3551
|
+
...failure,
|
|
3552
|
+
retryable: false,
|
|
3553
|
+
compactable: false,
|
|
3554
|
+
terminal: true,
|
|
3555
|
+
message
|
|
3556
|
+
};
|
|
3557
|
+
}
|
|
3558
|
+
|
|
3264
3559
|
// ../../packages/agent-framework/src/session/controller/retry-policy.ts
|
|
3265
3560
|
function defaultSetTimeout4(callback, delay) {
|
|
3266
3561
|
return setTimeout(callback, delay);
|
|
@@ -3269,42 +3564,49 @@ function defaultClearTimeout4(handle) {
|
|
|
3269
3564
|
clearTimeout(handle);
|
|
3270
3565
|
}
|
|
3271
3566
|
var AgentSessionRetryController = class {
|
|
3272
|
-
constructor(retry, emit, removeTrailingAssistantError2, continueTurn) {
|
|
3567
|
+
constructor(retry, emit, removeTrailingAssistantError2, continueTurn, setRecoveryState) {
|
|
3273
3568
|
this.retry = retry;
|
|
3274
3569
|
this.emit = emit;
|
|
3275
3570
|
this.removeTrailingAssistantError = removeTrailingAssistantError2;
|
|
3276
3571
|
this.continueTurn = continueTurn;
|
|
3572
|
+
this.setRecoveryState = setRecoveryState;
|
|
3277
3573
|
}
|
|
3278
3574
|
retry;
|
|
3279
3575
|
emit;
|
|
3280
3576
|
removeTrailingAssistantError;
|
|
3281
3577
|
continueTurn;
|
|
3578
|
+
setRecoveryState;
|
|
3282
3579
|
retryAttempt = 0;
|
|
3283
3580
|
retryTimer;
|
|
3284
3581
|
pendingRetry;
|
|
3285
3582
|
resolvePendingRetry;
|
|
3583
|
+
get policy() {
|
|
3584
|
+
return this.retry;
|
|
3585
|
+
}
|
|
3286
3586
|
get hasPendingRetry() {
|
|
3287
3587
|
return this.retryTimer !== void 0 || this.pendingRetry !== void 0;
|
|
3288
3588
|
}
|
|
3289
3589
|
waitForRetry() {
|
|
3290
3590
|
return this.pendingRetry ?? Promise.resolve();
|
|
3291
3591
|
}
|
|
3292
|
-
async handleTurnEnd(message) {
|
|
3592
|
+
async handleTurnEnd(message, failure) {
|
|
3293
3593
|
if (!this.retry || !message || message.role !== "assistant") {
|
|
3294
3594
|
return;
|
|
3295
3595
|
}
|
|
3296
|
-
|
|
3297
|
-
if (!errorMessage) {
|
|
3596
|
+
if (!failure) {
|
|
3298
3597
|
if (this.retryAttempt > 0) {
|
|
3299
3598
|
this.emit({ type: "retry_succeeded", attempts: this.retryAttempt });
|
|
3599
|
+
this.emit({ type: "turn_retry_succeeded", attempts: this.retryAttempt });
|
|
3300
3600
|
this.retryAttempt = 0;
|
|
3601
|
+
this.setRecoveryState("none");
|
|
3301
3602
|
this.resolvePending();
|
|
3302
3603
|
}
|
|
3303
3604
|
return;
|
|
3304
3605
|
}
|
|
3305
|
-
if (!
|
|
3606
|
+
if (!failure.retryable) {
|
|
3306
3607
|
if (this.retryAttempt > 0) {
|
|
3307
3608
|
this.retryAttempt = 0;
|
|
3609
|
+
this.setRecoveryState("none");
|
|
3308
3610
|
this.resolvePending();
|
|
3309
3611
|
}
|
|
3310
3612
|
return;
|
|
@@ -3312,28 +3614,41 @@ var AgentSessionRetryController = class {
|
|
|
3312
3614
|
const maxRetries = this.retry.maxRetries ?? 3;
|
|
3313
3615
|
this.retryAttempt += 1;
|
|
3314
3616
|
if (this.retryAttempt > maxRetries) {
|
|
3315
|
-
|
|
3617
|
+
const terminalFailure = asTerminalFailure(failure);
|
|
3618
|
+
this.emit({ type: "retry_exhausted", errorMessage: failure.message, maxRetries });
|
|
3619
|
+
this.emit({ type: "turn_failed_terminal", failure: terminalFailure, message });
|
|
3620
|
+
this.emit({ type: "turn_settled" });
|
|
3316
3621
|
this.retryAttempt = 0;
|
|
3622
|
+
this.setRecoveryState("terminal");
|
|
3317
3623
|
this.resolvePending();
|
|
3318
3624
|
return;
|
|
3319
3625
|
}
|
|
3320
3626
|
const attempt = this.retryAttempt;
|
|
3321
3627
|
const delayMs = (this.retry.baseDelayMs ?? 2e3) * 2 ** (attempt - 1);
|
|
3322
3628
|
this.ensurePending();
|
|
3323
|
-
this.
|
|
3629
|
+
this.setRecoveryState("retry_pending");
|
|
3630
|
+
this.emit({ type: "turn_recovery_pending", recovery: "retry", failure, attempt, maxRetries, delayMs });
|
|
3631
|
+
this.emit({ type: "retry_scheduled", errorMessage: failure.message, attempt, maxRetries, delayMs });
|
|
3324
3632
|
this.cancelTimerOnly();
|
|
3325
3633
|
const setTimer = this.retry.setTimeout ?? defaultSetTimeout4;
|
|
3326
3634
|
this.retryTimer = setTimer(() => {
|
|
3327
3635
|
this.retryTimer = void 0;
|
|
3636
|
+
this.setRecoveryState("retrying");
|
|
3328
3637
|
this.emit({ type: "retry_start", attempt, maxRetries });
|
|
3638
|
+
this.emit({ type: "turn_retry_started", attempt, maxRetries, failure });
|
|
3329
3639
|
this.removeTrailingAssistantError();
|
|
3330
3640
|
void this.continueTurn().catch((error) => {
|
|
3641
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3642
|
+
const terminalFailure = asTerminalFailure(failure, errorMessage);
|
|
3331
3643
|
this.emit({
|
|
3332
3644
|
type: "retry_exhausted",
|
|
3333
|
-
errorMessage
|
|
3645
|
+
errorMessage,
|
|
3334
3646
|
maxRetries
|
|
3335
3647
|
});
|
|
3648
|
+
this.emit({ type: "turn_failed_terminal", failure: terminalFailure, message });
|
|
3649
|
+
this.emit({ type: "turn_settled" });
|
|
3336
3650
|
this.retryAttempt = 0;
|
|
3651
|
+
this.setRecoveryState("terminal");
|
|
3337
3652
|
this.resolvePending();
|
|
3338
3653
|
});
|
|
3339
3654
|
}, delayMs);
|
|
@@ -3464,6 +3779,33 @@ var AgentSessionRuntimeGuard = class {
|
|
|
3464
3779
|
}
|
|
3465
3780
|
};
|
|
3466
3781
|
|
|
3782
|
+
// ../../packages/agent-framework/src/session/controller/runtime-phase-policy.ts
|
|
3783
|
+
function classifyControllerRuntimeError(params) {
|
|
3784
|
+
const errorMessage = params.error instanceof Error ? params.error.message : String(params.error);
|
|
3785
|
+
return createFailureClassification({ errorMessage, phase: params.phase }, params.retry, params.classifyFailure);
|
|
3786
|
+
}
|
|
3787
|
+
async function runAgentSessionRuntimePhase(params) {
|
|
3788
|
+
try {
|
|
3789
|
+
return await params.action();
|
|
3790
|
+
} catch (error) {
|
|
3791
|
+
const failure = classifyControllerRuntimeError({
|
|
3792
|
+
error,
|
|
3793
|
+
phase: params.phase,
|
|
3794
|
+
retry: params.retry,
|
|
3795
|
+
classifyFailure: params.classifyFailure
|
|
3796
|
+
});
|
|
3797
|
+
if (failure.userAbort) {
|
|
3798
|
+
params.setRecoveryState("cancelled");
|
|
3799
|
+
params.emit({ type: "turn_cancelled", reason: failure.message });
|
|
3800
|
+
} else {
|
|
3801
|
+
params.setRecoveryState("terminal");
|
|
3802
|
+
params.emit({ type: "turn_failed_terminal", failure: asTerminalFailure(failure) });
|
|
3803
|
+
}
|
|
3804
|
+
params.emit({ type: "turn_settled" });
|
|
3805
|
+
throw error;
|
|
3806
|
+
}
|
|
3807
|
+
}
|
|
3808
|
+
|
|
3467
3809
|
// ../../packages/agent-framework/src/session/controller/session-sync.ts
|
|
3468
3810
|
function getConversationMessages(messages) {
|
|
3469
3811
|
return messages.filter(
|
|
@@ -3568,6 +3910,161 @@ function reduceAgentSessionLifecycle(state, input) {
|
|
|
3568
3910
|
}
|
|
3569
3911
|
}
|
|
3570
3912
|
|
|
3913
|
+
// ../../packages/agent-framework/src/session/controller/turn-lifecycle-policy.ts
|
|
3914
|
+
function isAgentSessionRecoveryActive(state) {
|
|
3915
|
+
return state === "retry_pending" || state === "retrying" || state === "compacting";
|
|
3916
|
+
}
|
|
3917
|
+
function createRuntimeGuardFailure(reason) {
|
|
3918
|
+
return {
|
|
3919
|
+
kind: "runtime_guard",
|
|
3920
|
+
retryable: false,
|
|
3921
|
+
compactable: false,
|
|
3922
|
+
userAbort: false,
|
|
3923
|
+
terminal: true,
|
|
3924
|
+
message: reason
|
|
3925
|
+
};
|
|
3926
|
+
}
|
|
3927
|
+
function classifyControllerTurnFailure(params) {
|
|
3928
|
+
if (!isAssistantFailureMessage(params.message)) {
|
|
3929
|
+
return void 0;
|
|
3930
|
+
}
|
|
3931
|
+
const errorMessage = params.message.errorMessage || (params.message.stopReason === "aborted" ? "Request was aborted" : "assistant response failed");
|
|
3932
|
+
return createFailureClassification(
|
|
3933
|
+
{ errorMessage, message: params.message, phase: "stream" },
|
|
3934
|
+
params.retry,
|
|
3935
|
+
params.classifyFailure
|
|
3936
|
+
);
|
|
3937
|
+
}
|
|
3938
|
+
async function handleAgentSessionTurnEndRuntimePolicies(params) {
|
|
3939
|
+
if (params.disposed || params.runtimeGuardTriggered) {
|
|
3940
|
+
return;
|
|
3941
|
+
}
|
|
3942
|
+
const failure = classifyControllerTurnFailure({
|
|
3943
|
+
message: params.message,
|
|
3944
|
+
retry: params.retry,
|
|
3945
|
+
classifyFailure: params.classifyFailure
|
|
3946
|
+
});
|
|
3947
|
+
if (failure?.userAbort) {
|
|
3948
|
+
params.cancelRetry();
|
|
3949
|
+
params.setRecoveryState("cancelled");
|
|
3950
|
+
params.emit({ type: "turn_cancelled", reason: failure.message, message: params.message });
|
|
3951
|
+
params.emit({ type: "turn_settled" });
|
|
3952
|
+
return;
|
|
3953
|
+
}
|
|
3954
|
+
const compactDecision = params.getAutoCompactDecision?.({
|
|
3955
|
+
agent: params.agent,
|
|
3956
|
+
sessionManager: params.sessionManager,
|
|
3957
|
+
cwd: params.cwd,
|
|
3958
|
+
message: params.message,
|
|
3959
|
+
messages: params.agent.state.messages.slice()
|
|
3960
|
+
});
|
|
3961
|
+
if (failure?.compactable) {
|
|
3962
|
+
params.scheduleAutoCompact(compactDecision ?? { reason: "overflow", willRetry: true }, failure);
|
|
3963
|
+
return;
|
|
3964
|
+
}
|
|
3965
|
+
if (failure && compactDecision?.reason === "overflow") {
|
|
3966
|
+
params.scheduleAutoCompact(compactDecision, failure);
|
|
3967
|
+
return;
|
|
3968
|
+
}
|
|
3969
|
+
if (failure?.retryable && compactDecision?.reason === "threshold") {
|
|
3970
|
+
params.scheduleAutoCompact({ reason: "threshold", willRetry: true }, failure);
|
|
3971
|
+
return;
|
|
3972
|
+
}
|
|
3973
|
+
if (failure) {
|
|
3974
|
+
if (failure.retryable) {
|
|
3975
|
+
await params.handleRetryTurnEnd(params.message, failure);
|
|
3976
|
+
return;
|
|
3977
|
+
}
|
|
3978
|
+
await params.handleRetryTurnEnd(params.message, failure);
|
|
3979
|
+
params.setRecoveryState("terminal");
|
|
3980
|
+
params.emit({ type: "turn_failed_terminal", failure: asTerminalFailure(failure), message: params.message });
|
|
3981
|
+
params.emit({ type: "turn_settled" });
|
|
3982
|
+
return;
|
|
3983
|
+
}
|
|
3984
|
+
await params.handleRetryTurnEnd(params.message);
|
|
3985
|
+
if (isAssistantTerminalCompletion(params.message)) {
|
|
3986
|
+
params.emit({ type: "turn_completed", message: params.message, toolResults: params.toolResults });
|
|
3987
|
+
const postTurnCompactDecision = compactDecision ?? params.getAutoCompactDecision?.({
|
|
3988
|
+
agent: params.agent,
|
|
3989
|
+
sessionManager: params.sessionManager,
|
|
3990
|
+
cwd: params.cwd,
|
|
3991
|
+
message: params.message,
|
|
3992
|
+
messages: params.agent.state.messages.slice()
|
|
3993
|
+
});
|
|
3994
|
+
if (postTurnCompactDecision?.reason === "threshold") {
|
|
3995
|
+
params.scheduleAutoCompact(postTurnCompactDecision);
|
|
3996
|
+
return;
|
|
3997
|
+
}
|
|
3998
|
+
params.setRecoveryState("none");
|
|
3999
|
+
params.emit({ type: "turn_settled" });
|
|
4000
|
+
}
|
|
4001
|
+
}
|
|
4002
|
+
async function runAgentSessionControllerAutoCompact(params) {
|
|
4003
|
+
const emitSettled = params.emitSettled ?? true;
|
|
4004
|
+
const runAfterAgentEndHook = params.runAfterAgentEndHook ?? true;
|
|
4005
|
+
const cancelOnAbort = params.cancelOnAbort ?? true;
|
|
4006
|
+
params.setRecoveryState("compacting");
|
|
4007
|
+
params.emit({ type: "turn_compaction_started", reason: params.reason, willRetry: params.willRetry });
|
|
4008
|
+
try {
|
|
4009
|
+
const result = await runAgentSessionCompaction({
|
|
4010
|
+
reason: params.reason,
|
|
4011
|
+
willRetry: params.willRetry,
|
|
4012
|
+
compaction: params.compaction,
|
|
4013
|
+
agent: params.agent,
|
|
4014
|
+
sessionManager: params.sessionManager,
|
|
4015
|
+
cwd: params.cwd,
|
|
4016
|
+
emit: params.emit,
|
|
4017
|
+
removeTrailingAssistantError: params.removeTrailingAssistantError,
|
|
4018
|
+
replaceMessagesAndMarkSynced: params.replaceMessagesAndMarkSynced,
|
|
4019
|
+
markSyncedToAgentState: params.markSyncedToAgentState,
|
|
4020
|
+
continueTurn: params.continueTurn
|
|
4021
|
+
});
|
|
4022
|
+
if (!params.willRetry || result?.aborted) {
|
|
4023
|
+
params.setRecoveryState(result?.aborted && cancelOnAbort ? "cancelled" : "none");
|
|
4024
|
+
if (result?.aborted) {
|
|
4025
|
+
params.cancelRetry();
|
|
4026
|
+
if (cancelOnAbort) {
|
|
4027
|
+
params.emit({ type: "turn_cancelled", reason: "compaction_aborted" });
|
|
4028
|
+
}
|
|
4029
|
+
}
|
|
4030
|
+
if (emitSettled) {
|
|
4031
|
+
params.emit({ type: "turn_settled" });
|
|
4032
|
+
}
|
|
4033
|
+
if (!result?.aborted && runAfterAgentEndHook) {
|
|
4034
|
+
void params.handleAgentEndHook(params.agent.state.messages.slice());
|
|
4035
|
+
}
|
|
4036
|
+
}
|
|
4037
|
+
return result;
|
|
4038
|
+
} catch (error) {
|
|
4039
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4040
|
+
if (!params.willRetry && params.reason !== "overflow") {
|
|
4041
|
+
params.setRecoveryState("none");
|
|
4042
|
+
if (emitSettled) {
|
|
4043
|
+
params.emit({ type: "turn_settled" });
|
|
4044
|
+
}
|
|
4045
|
+
if (runAfterAgentEndHook) {
|
|
4046
|
+
void params.handleAgentEndHook(params.agent.state.messages.slice());
|
|
4047
|
+
}
|
|
4048
|
+
throw error;
|
|
4049
|
+
}
|
|
4050
|
+
const failure = asTerminalFailure(params.pendingFailure ?? {
|
|
4051
|
+
kind: "internal_error",
|
|
4052
|
+
retryable: false,
|
|
4053
|
+
compactable: false,
|
|
4054
|
+
userAbort: false,
|
|
4055
|
+
terminal: true,
|
|
4056
|
+
message: errorMessage
|
|
4057
|
+
}, errorMessage);
|
|
4058
|
+
params.cancelRetry();
|
|
4059
|
+
params.setRecoveryState("terminal");
|
|
4060
|
+
params.emit({ type: "turn_failed_terminal", failure });
|
|
4061
|
+
params.emit({ type: "turn_settled" });
|
|
4062
|
+
throw error;
|
|
4063
|
+
} finally {
|
|
4064
|
+
params.clearPendingFailure();
|
|
4065
|
+
}
|
|
4066
|
+
}
|
|
4067
|
+
|
|
3571
4068
|
// ../../packages/agent-framework/src/session/controller.ts
|
|
3572
4069
|
var AgentSessionController = class {
|
|
3573
4070
|
agent;
|
|
@@ -3589,6 +4086,9 @@ var AgentSessionController = class {
|
|
|
3589
4086
|
prepareTurn;
|
|
3590
4087
|
afterAgentEnd;
|
|
3591
4088
|
getAutoCompactDecision;
|
|
4089
|
+
classifyFailure;
|
|
4090
|
+
recoveryState = "none";
|
|
4091
|
+
pendingCompactionFailure;
|
|
3592
4092
|
lifecycleState = createInitialAgentSessionLifecycleState();
|
|
3593
4093
|
constructor(options) {
|
|
3594
4094
|
this.agent = options.agent;
|
|
@@ -3599,6 +4099,7 @@ var AgentSessionController = class {
|
|
|
3599
4099
|
this.prepareTurn = options.prepareTurn;
|
|
3600
4100
|
this.afterAgentEnd = options.afterAgentEnd;
|
|
3601
4101
|
this.getAutoCompactDecision = options.getAutoCompactDecision;
|
|
4102
|
+
this.classifyFailure = options.classifyFailure;
|
|
3602
4103
|
if (options.onEvent) {
|
|
3603
4104
|
this.listeners.add(options.onEvent);
|
|
3604
4105
|
}
|
|
@@ -3614,7 +4115,10 @@ var AgentSessionController = class {
|
|
|
3614
4115
|
options.retry,
|
|
3615
4116
|
(event) => this.emit(event),
|
|
3616
4117
|
() => this.removeTrailingAssistantError(),
|
|
3617
|
-
() => this.continue()
|
|
4118
|
+
() => this.continue(),
|
|
4119
|
+
(state) => {
|
|
4120
|
+
this.recoveryState = state;
|
|
4121
|
+
}
|
|
3618
4122
|
);
|
|
3619
4123
|
this.autoCompact = new AgentSessionAutoCompactScheduler({
|
|
3620
4124
|
retry: options.retry,
|
|
@@ -3634,6 +4138,7 @@ var AgentSessionController = class {
|
|
|
3634
4138
|
emit: (event) => this.emit(event),
|
|
3635
4139
|
getDisposed: () => this.disposed,
|
|
3636
4140
|
getRuntimeGuardTriggered: () => this.runtimeGuard.triggered,
|
|
4141
|
+
isBlockedByRuntimePolicy: () => this.isBlockedByRuntimePolicy(),
|
|
3637
4142
|
hasQueuedMessages: () => this.hasQueuedMessages,
|
|
3638
4143
|
isStreaming: () => this.isStreaming,
|
|
3639
4144
|
continueTurn: () => this.continue()
|
|
@@ -3649,7 +4154,8 @@ var AgentSessionController = class {
|
|
|
3649
4154
|
getDisposed: () => this.disposed,
|
|
3650
4155
|
getRuntimeGuardTriggered: () => this.runtimeGuard.triggered,
|
|
3651
4156
|
isStreaming: () => this.isStreaming,
|
|
3652
|
-
isBlockedByRuntimePolicy: () => this.
|
|
4157
|
+
isBlockedByRuntimePolicy: () => this.isBlockedByRuntimePolicy(),
|
|
4158
|
+
runPreRequestAutoCompact: () => this.runPreRequestAutoCompactIfNeeded(),
|
|
3653
4159
|
preparePromptMessages: (messages, promptOptions) => this.preparePromptMessages(messages, promptOptions),
|
|
3654
4160
|
continueTurn: () => this.continue(),
|
|
3655
4161
|
syncNewAgentMessages: () => this.syncNewAgentMessages()
|
|
@@ -3672,6 +4178,9 @@ var AgentSessionController = class {
|
|
|
3672
4178
|
get queuedInputsSnapshot() {
|
|
3673
4179
|
return this.queue.snapshot;
|
|
3674
4180
|
}
|
|
4181
|
+
get turnRecoveryState() {
|
|
4182
|
+
return this.recoveryState;
|
|
4183
|
+
}
|
|
3675
4184
|
get activeSessionMetadata() {
|
|
3676
4185
|
const metadata = this.sessionManager.getActiveSession()?.metadata;
|
|
3677
4186
|
return metadata ? { ...metadata } : void 0;
|
|
@@ -3680,10 +4189,7 @@ var AgentSessionController = class {
|
|
|
3680
4189
|
return this.lastSyncedMessageCount;
|
|
3681
4190
|
}
|
|
3682
4191
|
get runtimeContext() {
|
|
3683
|
-
return {
|
|
3684
|
-
systemPrompt: this.agent.state.systemPrompt,
|
|
3685
|
-
tools: this.agent.state.tools.slice()
|
|
3686
|
-
};
|
|
4192
|
+
return { systemPrompt: this.agent.state.systemPrompt, tools: this.agent.state.tools.slice() };
|
|
3687
4193
|
}
|
|
3688
4194
|
getRuntimeSnapshot() {
|
|
3689
4195
|
return {
|
|
@@ -3730,6 +4236,17 @@ var AgentSessionController = class {
|
|
|
3730
4236
|
}
|
|
3731
4237
|
async prompt(input, options) {
|
|
3732
4238
|
const messages = normalizePromptInput(input);
|
|
4239
|
+
if (this.isRecoveryActive()) {
|
|
4240
|
+
this.queue.enqueue(messages, options?.streamingBehavior ?? "followUp", {
|
|
4241
|
+
...options,
|
|
4242
|
+
streamingBehavior: options?.streamingBehavior ?? "followUp"
|
|
4243
|
+
});
|
|
4244
|
+
this.recordLifecycle({ type: "queued_input_added" });
|
|
4245
|
+
return;
|
|
4246
|
+
}
|
|
4247
|
+
if (this.recoveryState === "terminal" || this.recoveryState === "cancelled") {
|
|
4248
|
+
this.recoveryState = "none";
|
|
4249
|
+
}
|
|
3733
4250
|
if (options?.streamingBehavior) {
|
|
3734
4251
|
this.queue.enqueue(messages, options.streamingBehavior, options);
|
|
3735
4252
|
this.recordLifecycle({ type: "queued_input_added" });
|
|
@@ -3741,7 +4258,8 @@ var AgentSessionController = class {
|
|
|
3741
4258
|
if (this.isStreaming) {
|
|
3742
4259
|
throw new Error("Agent is already processing. Specify streamingBehavior ('steer' or 'followUp') to queue the message.");
|
|
3743
4260
|
}
|
|
3744
|
-
|
|
4261
|
+
await this.runPreRequestAutoCompactIfNeeded();
|
|
4262
|
+
const prepared = await this.runRuntimePhase("prepare", () => this.preparePromptMessages(messages, options));
|
|
3745
4263
|
if (prepared.handled) {
|
|
3746
4264
|
return;
|
|
3747
4265
|
}
|
|
@@ -3749,23 +4267,30 @@ var AgentSessionController = class {
|
|
|
3749
4267
|
if (prepared.systemPrompt !== void 0) {
|
|
3750
4268
|
this.agent.setSystemPrompt(prepared.systemPrompt);
|
|
3751
4269
|
}
|
|
3752
|
-
await this.agent.prompt(prepared.messages);
|
|
3753
|
-
await this.syncNewAgentMessages();
|
|
4270
|
+
await this.runRuntimePhase("request", () => this.agent.prompt(prepared.messages));
|
|
4271
|
+
await this.runRuntimePhase("post_turn", () => this.syncNewAgentMessages());
|
|
3754
4272
|
}
|
|
3755
4273
|
async continue() {
|
|
3756
4274
|
if (this.isStreaming) {
|
|
3757
4275
|
throw new Error("Agent is already processing. Wait for completion before continuing.");
|
|
3758
4276
|
}
|
|
4277
|
+
await this.runPreRequestAutoCompactIfNeeded();
|
|
3759
4278
|
this.recordLifecycle({ type: "prompt_started" });
|
|
3760
|
-
await this.agent.continue();
|
|
3761
|
-
await this.syncNewAgentMessages();
|
|
4279
|
+
await this.runRuntimePhase("request", () => this.agent.continue());
|
|
4280
|
+
await this.runRuntimePhase("post_turn", () => this.syncNewAgentMessages());
|
|
3762
4281
|
}
|
|
3763
4282
|
abort() {
|
|
3764
4283
|
this.recordLifecycle({ type: "abort" });
|
|
4284
|
+
const cancelPendingRecovery = this.isRecoveryActive() && !this.isStreaming;
|
|
3765
4285
|
this.retryController.cancel();
|
|
3766
4286
|
this.autoCompact.cancel();
|
|
3767
4287
|
this.queueDispatcher.cancel();
|
|
3768
4288
|
this.autoContinue.cancel();
|
|
4289
|
+
if (cancelPendingRecovery) {
|
|
4290
|
+
this.recoveryState = "cancelled";
|
|
4291
|
+
this.emit({ type: "turn_cancelled", reason: "user_abort" });
|
|
4292
|
+
this.emit({ type: "turn_settled" });
|
|
4293
|
+
}
|
|
3769
4294
|
this.agent.abort();
|
|
3770
4295
|
}
|
|
3771
4296
|
waitForIdle() {
|
|
@@ -3774,25 +4299,37 @@ var AgentSessionController = class {
|
|
|
3774
4299
|
async waitForSettled() {
|
|
3775
4300
|
while (true) {
|
|
3776
4301
|
await this.agent.waitForIdle();
|
|
3777
|
-
if (!this.
|
|
4302
|
+
if (!this.hasPendingRuntimePolicy()) {
|
|
3778
4303
|
return;
|
|
3779
4304
|
}
|
|
3780
|
-
await this.retryController.waitForRetry();
|
|
4305
|
+
await Promise.all([this.retryController.waitForRetry(), this.autoCompact.waitForAutoCompact(), this.autoContinue.waitForAutoContinue(), this.queueDispatcher.waitForDispatch()]);
|
|
3781
4306
|
}
|
|
3782
4307
|
}
|
|
3783
|
-
async runAutoCompact(reason, willRetry = false) {
|
|
3784
|
-
return
|
|
4308
|
+
async runAutoCompact(reason, willRetry = false, options) {
|
|
4309
|
+
return runAgentSessionControllerAutoCompact({
|
|
3785
4310
|
reason,
|
|
3786
4311
|
willRetry,
|
|
3787
4312
|
compaction: this.compaction,
|
|
3788
4313
|
agent: this.agent,
|
|
3789
4314
|
sessionManager: this.sessionManager,
|
|
3790
4315
|
cwd: this.cwd,
|
|
4316
|
+
pendingFailure: this.pendingCompactionFailure,
|
|
3791
4317
|
emit: (event) => this.emit(event),
|
|
4318
|
+
setRecoveryState: (state) => {
|
|
4319
|
+
this.recoveryState = state;
|
|
4320
|
+
},
|
|
4321
|
+
cancelRetry: () => this.retryController.cancel(),
|
|
4322
|
+
clearPendingFailure: () => {
|
|
4323
|
+
this.pendingCompactionFailure = void 0;
|
|
4324
|
+
},
|
|
3792
4325
|
removeTrailingAssistantError: () => this.removeTrailingAssistantError(),
|
|
3793
|
-
replaceMessagesAndMarkSynced: (messages,
|
|
4326
|
+
replaceMessagesAndMarkSynced: (messages, options2) => this.replaceMessagesAndMarkSynced(messages, options2),
|
|
3794
4327
|
markSyncedToAgentState: () => this.markSyncedToAgentState(),
|
|
3795
|
-
continueTurn: () => this.continue()
|
|
4328
|
+
continueTurn: () => this.continue(),
|
|
4329
|
+
handleAgentEndHook: (messages) => this.handleAgentEndHook(messages),
|
|
4330
|
+
emitSettled: options?.emitSettled,
|
|
4331
|
+
runAfterAgentEndHook: options?.runAfterAgentEndHook,
|
|
4332
|
+
cancelOnAbort: options?.cancelOnAbort
|
|
3796
4333
|
});
|
|
3797
4334
|
}
|
|
3798
4335
|
dispose() {
|
|
@@ -3814,9 +4351,23 @@ var AgentSessionController = class {
|
|
|
3814
4351
|
this.queue.replaceText(search, replacement);
|
|
3815
4352
|
}
|
|
3816
4353
|
requestQueueDispatch() {
|
|
3817
|
-
if (this.queue.length > 0)
|
|
3818
|
-
|
|
3819
|
-
|
|
4354
|
+
if (this.queue.length > 0) this.queueDispatcher.schedule();
|
|
4355
|
+
}
|
|
4356
|
+
async runPreRequestAutoCompactIfNeeded() {
|
|
4357
|
+
return runPreRequestAutoCompact({
|
|
4358
|
+
disposed: this.disposed,
|
|
4359
|
+
runtimeGuardTriggered: this.runtimeGuard.triggered,
|
|
4360
|
+
isStreaming: this.isStreaming,
|
|
4361
|
+
recoveryActive: this.isRecoveryActive(),
|
|
4362
|
+
agent: this.agent,
|
|
4363
|
+
sessionManager: this.sessionManager,
|
|
4364
|
+
cwd: this.cwd,
|
|
4365
|
+
getAutoCompactDecision: this.getAutoCompactDecision,
|
|
4366
|
+
runAutoCompact: () => this.runAutoCompact("threshold", false, { emitSettled: false, runAfterAgentEndHook: false, cancelOnAbort: false }).then(() => void 0),
|
|
4367
|
+
setRecoveryState: (state) => {
|
|
4368
|
+
this.recoveryState = state;
|
|
4369
|
+
}
|
|
4370
|
+
});
|
|
3820
4371
|
}
|
|
3821
4372
|
handleAgentEvent(event) {
|
|
3822
4373
|
this.emit({ type: "agent_event", event });
|
|
@@ -3837,7 +4388,7 @@ var AgentSessionController = class {
|
|
|
3837
4388
|
if (event.type === "turn_end") {
|
|
3838
4389
|
void this.syncNewAgentMessages();
|
|
3839
4390
|
this.recordLifecycle({ type: "turn_end_success" });
|
|
3840
|
-
void this.handleTurnEndRuntimePolicies(event.message);
|
|
4391
|
+
void this.handleTurnEndRuntimePolicies(event.message, event.toolResults);
|
|
3841
4392
|
}
|
|
3842
4393
|
if (event.type === "agent_end") {
|
|
3843
4394
|
this.recordLifecycle({ type: "agent_end" });
|
|
@@ -3874,31 +4425,29 @@ var AgentSessionController = class {
|
|
|
3874
4425
|
replaceMessagesAndMarkSynced: (messages, options) => this.replaceMessagesAndMarkSynced(messages, options)
|
|
3875
4426
|
});
|
|
3876
4427
|
}
|
|
3877
|
-
async handleTurnEndRuntimePolicies(message) {
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
await this.retryController.handleTurnEnd(message);
|
|
3884
|
-
}
|
|
3885
|
-
const compactDecision = this.getAutoCompactDecision?.({
|
|
4428
|
+
async handleTurnEndRuntimePolicies(message, toolResults = []) {
|
|
4429
|
+
return handleAgentSessionTurnEndRuntimePolicies({
|
|
4430
|
+
disposed: this.disposed,
|
|
4431
|
+
runtimeGuardTriggered: this.runtimeGuard.triggered,
|
|
4432
|
+
message,
|
|
4433
|
+
toolResults,
|
|
3886
4434
|
agent: this.agent,
|
|
3887
4435
|
sessionManager: this.sessionManager,
|
|
3888
4436
|
cwd: this.cwd,
|
|
3889
|
-
|
|
3890
|
-
|
|
4437
|
+
getAutoCompactDecision: this.getAutoCompactDecision,
|
|
4438
|
+
classifyFailure: this.classifyFailure,
|
|
4439
|
+
retry: this.retryController.policy,
|
|
4440
|
+
emit: (event) => this.emit(event),
|
|
4441
|
+
setRecoveryState: (state) => {
|
|
4442
|
+
this.recoveryState = state;
|
|
4443
|
+
},
|
|
4444
|
+
handleRetryTurnEnd: (turnMessage, failure) => this.retryController.handleTurnEnd(turnMessage, failure),
|
|
4445
|
+
cancelRetry: () => this.retryController.cancel(),
|
|
4446
|
+
scheduleAutoCompact: (decision, failure) => this.scheduleAutoCompact(decision, failure)
|
|
3891
4447
|
});
|
|
3892
|
-
if (compactDecision) {
|
|
3893
|
-
this.scheduleAutoCompact(compactDecision);
|
|
3894
|
-
return;
|
|
3895
|
-
}
|
|
3896
|
-
if (assistantError) {
|
|
3897
|
-
await this.retryController.handleTurnEnd(message);
|
|
3898
|
-
}
|
|
3899
4448
|
}
|
|
3900
4449
|
async handleAgentEndHook(messages) {
|
|
3901
|
-
if (this.disposed || this.runtimeGuard.triggered) {
|
|
4450
|
+
if (this.disposed || this.runtimeGuard.triggered || this.isBlockedByRuntimePolicy()) {
|
|
3902
4451
|
return;
|
|
3903
4452
|
}
|
|
3904
4453
|
if (this.afterAgentEnd) {
|
|
@@ -3933,8 +4482,36 @@ var AgentSessionController = class {
|
|
|
3933
4482
|
recordToolExecutionEndForGuard(event) {
|
|
3934
4483
|
this.runtimeGuard.recordToolExecutionEnd(event);
|
|
3935
4484
|
}
|
|
3936
|
-
|
|
4485
|
+
async runRuntimePhase(phase, action) {
|
|
4486
|
+
return runAgentSessionRuntimePhase({
|
|
4487
|
+
phase,
|
|
4488
|
+
action,
|
|
4489
|
+
retry: this.retryController.policy,
|
|
4490
|
+
classifyFailure: this.classifyFailure,
|
|
4491
|
+
emit: (event) => this.emit(event),
|
|
4492
|
+
setRecoveryState: (state) => {
|
|
4493
|
+
this.recoveryState = state;
|
|
4494
|
+
}
|
|
4495
|
+
});
|
|
4496
|
+
}
|
|
4497
|
+
isRecoveryActive() {
|
|
4498
|
+
return isAgentSessionRecoveryActive(this.recoveryState);
|
|
4499
|
+
}
|
|
4500
|
+
isBlockedByRuntimePolicy() {
|
|
4501
|
+
return this.recoveryState !== "none" || this.retryController.hasPendingRetry || this.autoCompact.hasPendingAutoCompact;
|
|
4502
|
+
}
|
|
4503
|
+
hasPendingRuntimePolicy() {
|
|
4504
|
+
return this.retryController.hasPendingRetry || this.autoCompact.hasPendingAutoCompact || this.autoContinue.hasPendingAutoContinue || this.queueDispatcher.hasPendingDispatch;
|
|
4505
|
+
}
|
|
4506
|
+
scheduleAutoCompact(decision, failure) {
|
|
3937
4507
|
this.recordLifecycle({ type: "auto_compact_scheduled" });
|
|
4508
|
+
if (failure) {
|
|
4509
|
+
this.pendingCompactionFailure = failure;
|
|
4510
|
+
this.recoveryState = "compacting";
|
|
4511
|
+
this.emit({ type: "turn_recovery_pending", recovery: "compaction", failure });
|
|
4512
|
+
} else if (decision.reason === "threshold") {
|
|
4513
|
+
this.recoveryState = "compacting";
|
|
4514
|
+
}
|
|
3938
4515
|
this.autoCompact.schedule(decision);
|
|
3939
4516
|
}
|
|
3940
4517
|
triggerRuntimeGuard(toolName, repeatCount, reason) {
|
|
@@ -3946,7 +4523,13 @@ var AgentSessionController = class {
|
|
|
3946
4523
|
this.autoCompact.cancel();
|
|
3947
4524
|
this.queueDispatcher.cancel();
|
|
3948
4525
|
this.autoContinue.cancel();
|
|
4526
|
+
this.recoveryState = "terminal";
|
|
3949
4527
|
this.emit({ type: "runtime_guard_triggered", toolName, repeatCount, reason });
|
|
4528
|
+
this.emit({
|
|
4529
|
+
type: "turn_failed_terminal",
|
|
4530
|
+
failure: createRuntimeGuardFailure(reason)
|
|
4531
|
+
});
|
|
4532
|
+
this.emit({ type: "turn_settled" });
|
|
3950
4533
|
this.agent.abort();
|
|
3951
4534
|
}
|
|
3952
4535
|
emit(event) {
|
|
@@ -9023,7 +9606,10 @@ export {
|
|
|
9023
9606
|
ManageTodoListParamsSchema,
|
|
9024
9607
|
executeManageTodoList,
|
|
9025
9608
|
maybeAdvanceTodoExecutionState,
|
|
9609
|
+
estimateTokens,
|
|
9026
9610
|
calculateTotalTokens,
|
|
9611
|
+
estimateContextTokens,
|
|
9612
|
+
getAutoCompactTokenLimit,
|
|
9027
9613
|
findFirstKeptEntryId,
|
|
9028
9614
|
createCompactionSummary,
|
|
9029
9615
|
createSessionManager,
|