@protolabsai/proto 0.51.2 → 0.52.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/cli.js +2263 -2085
- package/package.json +2 -2
package/cli.js
CHANGED
|
@@ -168684,7 +168684,7 @@ __export(geminiContentGenerator_exports, {
|
|
|
168684
168684
|
createGeminiContentGenerator: () => createGeminiContentGenerator
|
|
168685
168685
|
});
|
|
168686
168686
|
function createGeminiContentGenerator(config2, gcConfig) {
|
|
168687
|
-
const version2 = "0.
|
|
168687
|
+
const version2 = "0.52.0";
|
|
168688
168688
|
const userAgent2 = config2.userAgent || `QwenCode/${version2} (${process.platform}; ${process.arch})`;
|
|
168689
168689
|
const baseHeaders = {
|
|
168690
168690
|
"User-Agent": userAgent2
|
|
@@ -168957,382 +168957,434 @@ var init_rateLimit = __esm({
|
|
|
168957
168957
|
}
|
|
168958
168958
|
});
|
|
168959
168959
|
|
|
168960
|
-
//
|
|
168961
|
-
function
|
|
168962
|
-
|
|
168963
|
-
a2.splice(i4 + 1, 0, v2);
|
|
168964
|
-
}
|
|
168965
|
-
function findIndexFromEnd(a2, predicate) {
|
|
168966
|
-
for (let i4 = a2.length - 1; i4 >= 0; i4--) {
|
|
168967
|
-
if (predicate(a2[i4])) {
|
|
168968
|
-
return i4;
|
|
168969
|
-
}
|
|
168970
|
-
}
|
|
168971
|
-
return -1;
|
|
168960
|
+
// packages/core/dist/src/utils/contextLengthError.js
|
|
168961
|
+
function parseInteger(value) {
|
|
168962
|
+
return Number.parseInt(value.replace(/,/g, ""), 10);
|
|
168972
168963
|
}
|
|
168973
|
-
|
|
168974
|
-
|
|
168975
|
-
|
|
168976
|
-
|
|
168977
|
-
|
|
168978
|
-
|
|
168979
|
-
E_CANCELED = new Error("request for lock canceled");
|
|
168980
|
-
__awaiter$2 = function(thisArg, _arguments, P2, generator) {
|
|
168981
|
-
function adopt(value) {
|
|
168982
|
-
return value instanceof P2 ? value : new P2(function(resolve37) {
|
|
168983
|
-
resolve37(value);
|
|
168984
|
-
});
|
|
168985
|
-
}
|
|
168986
|
-
__name(adopt, "adopt");
|
|
168987
|
-
return new (P2 || (P2 = Promise))(function(resolve37, reject) {
|
|
168988
|
-
function fulfilled(value) {
|
|
168989
|
-
try {
|
|
168990
|
-
step(generator.next(value));
|
|
168991
|
-
} catch (e4) {
|
|
168992
|
-
reject(e4);
|
|
168993
|
-
}
|
|
168994
|
-
}
|
|
168995
|
-
__name(fulfilled, "fulfilled");
|
|
168996
|
-
function rejected(value) {
|
|
168997
|
-
try {
|
|
168998
|
-
step(generator["throw"](value));
|
|
168999
|
-
} catch (e4) {
|
|
169000
|
-
reject(e4);
|
|
169001
|
-
}
|
|
169002
|
-
}
|
|
169003
|
-
__name(rejected, "rejected");
|
|
169004
|
-
function step(result) {
|
|
169005
|
-
result.done ? resolve37(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
169006
|
-
}
|
|
169007
|
-
__name(step, "step");
|
|
169008
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
169009
|
-
});
|
|
169010
|
-
};
|
|
169011
|
-
Semaphore = class {
|
|
169012
|
-
static {
|
|
169013
|
-
__name(this, "Semaphore");
|
|
169014
|
-
}
|
|
169015
|
-
constructor(_value, _cancelError = E_CANCELED) {
|
|
169016
|
-
this._value = _value;
|
|
169017
|
-
this._cancelError = _cancelError;
|
|
169018
|
-
this._queue = [];
|
|
169019
|
-
this._weightedWaiters = [];
|
|
169020
|
-
}
|
|
169021
|
-
acquire(weight = 1, priority = 0) {
|
|
169022
|
-
if (weight <= 0)
|
|
169023
|
-
throw new Error(`invalid weight ${weight}: must be positive`);
|
|
169024
|
-
return new Promise((resolve37, reject) => {
|
|
169025
|
-
const task = { resolve: resolve37, reject, weight, priority };
|
|
169026
|
-
const i4 = findIndexFromEnd(this._queue, (other2) => priority <= other2.priority);
|
|
169027
|
-
if (i4 === -1 && weight <= this._value) {
|
|
169028
|
-
this._dispatchItem(task);
|
|
169029
|
-
} else {
|
|
169030
|
-
this._queue.splice(i4 + 1, 0, task);
|
|
169031
|
-
}
|
|
169032
|
-
});
|
|
169033
|
-
}
|
|
169034
|
-
runExclusive(callback_1) {
|
|
169035
|
-
return __awaiter$2(this, arguments, void 0, function* (callback, weight = 1, priority = 0) {
|
|
169036
|
-
const [value, release2] = yield this.acquire(weight, priority);
|
|
169037
|
-
try {
|
|
169038
|
-
return yield callback(value);
|
|
169039
|
-
} finally {
|
|
169040
|
-
release2();
|
|
169041
|
-
}
|
|
169042
|
-
});
|
|
169043
|
-
}
|
|
169044
|
-
waitForUnlock(weight = 1, priority = 0) {
|
|
169045
|
-
if (weight <= 0)
|
|
169046
|
-
throw new Error(`invalid weight ${weight}: must be positive`);
|
|
169047
|
-
if (this._couldLockImmediately(weight, priority)) {
|
|
169048
|
-
return Promise.resolve();
|
|
169049
|
-
} else {
|
|
169050
|
-
return new Promise((resolve37) => {
|
|
169051
|
-
if (!this._weightedWaiters[weight - 1])
|
|
169052
|
-
this._weightedWaiters[weight - 1] = [];
|
|
169053
|
-
insertSorted(this._weightedWaiters[weight - 1], { resolve: resolve37, priority });
|
|
169054
|
-
});
|
|
169055
|
-
}
|
|
169056
|
-
}
|
|
169057
|
-
isLocked() {
|
|
169058
|
-
return this._value <= 0;
|
|
169059
|
-
}
|
|
169060
|
-
getValue() {
|
|
169061
|
-
return this._value;
|
|
169062
|
-
}
|
|
169063
|
-
setValue(value) {
|
|
169064
|
-
this._value = value;
|
|
169065
|
-
this._dispatchQueue();
|
|
169066
|
-
}
|
|
169067
|
-
release(weight = 1) {
|
|
169068
|
-
if (weight <= 0)
|
|
169069
|
-
throw new Error(`invalid weight ${weight}: must be positive`);
|
|
169070
|
-
this._value += weight;
|
|
169071
|
-
this._dispatchQueue();
|
|
169072
|
-
}
|
|
169073
|
-
cancel() {
|
|
169074
|
-
this._queue.forEach((entry) => entry.reject(this._cancelError));
|
|
169075
|
-
this._queue = [];
|
|
169076
|
-
}
|
|
169077
|
-
_dispatchQueue() {
|
|
169078
|
-
this._drainUnlockWaiters();
|
|
169079
|
-
while (this._queue.length > 0 && this._queue[0].weight <= this._value) {
|
|
169080
|
-
this._dispatchItem(this._queue.shift());
|
|
169081
|
-
this._drainUnlockWaiters();
|
|
169082
|
-
}
|
|
169083
|
-
}
|
|
169084
|
-
_dispatchItem(item) {
|
|
169085
|
-
const previousValue = this._value;
|
|
169086
|
-
this._value -= item.weight;
|
|
169087
|
-
item.resolve([previousValue, this._newReleaser(item.weight)]);
|
|
169088
|
-
}
|
|
169089
|
-
_newReleaser(weight) {
|
|
169090
|
-
let called = false;
|
|
169091
|
-
return () => {
|
|
169092
|
-
if (called)
|
|
169093
|
-
return;
|
|
169094
|
-
called = true;
|
|
169095
|
-
this.release(weight);
|
|
169096
|
-
};
|
|
169097
|
-
}
|
|
169098
|
-
_drainUnlockWaiters() {
|
|
169099
|
-
if (this._queue.length === 0) {
|
|
169100
|
-
for (let weight = this._value; weight > 0; weight--) {
|
|
169101
|
-
const waiters = this._weightedWaiters[weight - 1];
|
|
169102
|
-
if (!waiters)
|
|
169103
|
-
continue;
|
|
169104
|
-
waiters.forEach((waiter) => waiter.resolve());
|
|
169105
|
-
this._weightedWaiters[weight - 1] = [];
|
|
169106
|
-
}
|
|
169107
|
-
} else {
|
|
169108
|
-
const queuedPriority = this._queue[0].priority;
|
|
169109
|
-
for (let weight = this._value; weight > 0; weight--) {
|
|
169110
|
-
const waiters = this._weightedWaiters[weight - 1];
|
|
169111
|
-
if (!waiters)
|
|
169112
|
-
continue;
|
|
169113
|
-
const i4 = waiters.findIndex((waiter) => waiter.priority <= queuedPriority);
|
|
169114
|
-
(i4 === -1 ? waiters : waiters.splice(0, i4)).forEach((waiter) => waiter.resolve());
|
|
169115
|
-
}
|
|
169116
|
-
}
|
|
169117
|
-
}
|
|
169118
|
-
_couldLockImmediately(weight, priority) {
|
|
169119
|
-
return (this._queue.length === 0 || this._queue[0].priority < priority) && weight <= this._value;
|
|
169120
|
-
}
|
|
168964
|
+
function parseTokenCounts(text) {
|
|
168965
|
+
const greaterThanMatch = text.match(/(\d[\d,]*)\s*tokens?\s*>\s*(\d[\d,]*)/i);
|
|
168966
|
+
if (greaterThanMatch) {
|
|
168967
|
+
return {
|
|
168968
|
+
actualTokens: parseInteger(greaterThanMatch[1]),
|
|
168969
|
+
limitTokens: parseInteger(greaterThanMatch[2])
|
|
169121
168970
|
};
|
|
169122
|
-
|
|
169123
|
-
|
|
169124
|
-
|
|
169125
|
-
|
|
169126
|
-
|
|
169127
|
-
|
|
169128
|
-
});
|
|
169129
|
-
}
|
|
169130
|
-
__name(adopt, "adopt");
|
|
169131
|
-
return new (P2 || (P2 = Promise))(function(resolve37, reject) {
|
|
169132
|
-
function fulfilled(value) {
|
|
169133
|
-
try {
|
|
169134
|
-
step(generator.next(value));
|
|
169135
|
-
} catch (e4) {
|
|
169136
|
-
reject(e4);
|
|
169137
|
-
}
|
|
169138
|
-
}
|
|
169139
|
-
__name(fulfilled, "fulfilled");
|
|
169140
|
-
function rejected(value) {
|
|
169141
|
-
try {
|
|
169142
|
-
step(generator["throw"](value));
|
|
169143
|
-
} catch (e4) {
|
|
169144
|
-
reject(e4);
|
|
169145
|
-
}
|
|
169146
|
-
}
|
|
169147
|
-
__name(rejected, "rejected");
|
|
169148
|
-
function step(result) {
|
|
169149
|
-
result.done ? resolve37(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
169150
|
-
}
|
|
169151
|
-
__name(step, "step");
|
|
169152
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
169153
|
-
});
|
|
168971
|
+
}
|
|
168972
|
+
const openAiMatch = text.match(/maximum context length is\s*(\d[\d,]*)\s*tokens?[\s\S]*?(?:resulted in|requested|used)\s*(\d[\d,]*)\s*tokens?/i);
|
|
168973
|
+
if (openAiMatch) {
|
|
168974
|
+
return {
|
|
168975
|
+
actualTokens: parseInteger(openAiMatch[2]),
|
|
168976
|
+
limitTokens: parseInteger(openAiMatch[1])
|
|
169154
168977
|
};
|
|
169155
|
-
|
|
169156
|
-
|
|
169157
|
-
|
|
169158
|
-
|
|
169159
|
-
|
|
169160
|
-
this._semaphore = new Semaphore(1, cancelError);
|
|
169161
|
-
}
|
|
169162
|
-
acquire() {
|
|
169163
|
-
return __awaiter$1(this, arguments, void 0, function* (priority = 0) {
|
|
169164
|
-
const [, releaser] = yield this._semaphore.acquire(1, priority);
|
|
169165
|
-
return releaser;
|
|
169166
|
-
});
|
|
169167
|
-
}
|
|
169168
|
-
runExclusive(callback, priority = 0) {
|
|
169169
|
-
return this._semaphore.runExclusive(() => callback(), 1, priority);
|
|
169170
|
-
}
|
|
169171
|
-
isLocked() {
|
|
169172
|
-
return this._semaphore.isLocked();
|
|
169173
|
-
}
|
|
169174
|
-
waitForUnlock(priority = 0) {
|
|
169175
|
-
return this._semaphore.waitForUnlock(1, priority);
|
|
169176
|
-
}
|
|
169177
|
-
release() {
|
|
169178
|
-
if (this._semaphore.isLocked())
|
|
169179
|
-
this._semaphore.release();
|
|
169180
|
-
}
|
|
169181
|
-
cancel() {
|
|
169182
|
-
return this._semaphore.cancel();
|
|
169183
|
-
}
|
|
168978
|
+
}
|
|
168979
|
+
const maxContextLimitMatch = text.match(/maximum context length is\s*(\d[\d,]*)\s*tokens?/i);
|
|
168980
|
+
if (maxContextLimitMatch) {
|
|
168981
|
+
return {
|
|
168982
|
+
limitTokens: parseInteger(maxContextLimitMatch[1])
|
|
169184
168983
|
};
|
|
169185
168984
|
}
|
|
169186
|
-
|
|
169187
|
-
|
|
169188
|
-
|
|
169189
|
-
|
|
169190
|
-
|
|
169191
|
-
|
|
169192
|
-
function getFileLock(filePath) {
|
|
169193
|
-
if (!fileLocks.has(filePath)) {
|
|
169194
|
-
fileLocks.set(filePath, new Mutex());
|
|
168985
|
+
const inputExceedsMatch = text.match(/input\s+token\s+(?:count|length)[^\d]*(\d[\d,]*)[\s\S]*?exceed(?:s|ed)?[\s\S]*?(?:maximum|limit)[^\d]*(\d[\d,]*)/i);
|
|
168986
|
+
if (inputExceedsMatch) {
|
|
168987
|
+
return {
|
|
168988
|
+
actualTokens: parseInteger(inputExceedsMatch[1]),
|
|
168989
|
+
limitTokens: parseInteger(inputExceedsMatch[2])
|
|
168990
|
+
};
|
|
169195
168991
|
}
|
|
169196
|
-
return
|
|
168992
|
+
return {};
|
|
169197
168993
|
}
|
|
169198
|
-
|
|
169199
|
-
|
|
169200
|
-
|
|
169201
|
-
|
|
169202
|
-
|
|
169203
|
-
|
|
169204
|
-
});
|
|
169205
|
-
const results = [];
|
|
169206
|
-
for await (const line of rl) {
|
|
169207
|
-
if (results.length >= count)
|
|
169208
|
-
break;
|
|
169209
|
-
const trimmed2 = line.trim();
|
|
169210
|
-
if (trimmed2.length > 0) {
|
|
169211
|
-
results.push(JSON.parse(trimmed2));
|
|
169212
|
-
}
|
|
169213
|
-
}
|
|
169214
|
-
return results;
|
|
169215
|
-
} catch (error40) {
|
|
169216
|
-
if (error40.code !== "ENOENT") {
|
|
169217
|
-
debugLogger21.error(`Error reading first ${count} lines from ${filePath}:`, error40);
|
|
168994
|
+
function tryParseEmbeddedJson(text) {
|
|
168995
|
+
const trimmed2 = text.trim();
|
|
168996
|
+
if (trimmed2.startsWith("{") || trimmed2.startsWith("[")) {
|
|
168997
|
+
try {
|
|
168998
|
+
return JSON.parse(trimmed2);
|
|
168999
|
+
} catch {
|
|
169218
169000
|
}
|
|
169219
|
-
return [];
|
|
169220
169001
|
}
|
|
169221
|
-
|
|
169222
|
-
|
|
169002
|
+
const start2 = text.indexOf("{");
|
|
169003
|
+
const end = text.lastIndexOf("}");
|
|
169004
|
+
if (start2 === -1 || end <= start2) {
|
|
169005
|
+
return void 0;
|
|
169006
|
+
}
|
|
169223
169007
|
try {
|
|
169224
|
-
|
|
169225
|
-
|
|
169226
|
-
|
|
169227
|
-
|
|
169228
|
-
|
|
169229
|
-
|
|
169230
|
-
|
|
169231
|
-
|
|
169232
|
-
|
|
169233
|
-
|
|
169234
|
-
|
|
169235
|
-
|
|
169236
|
-
|
|
169237
|
-
} catch (error40) {
|
|
169238
|
-
if (error40.code !== "ENOENT") {
|
|
169239
|
-
debugLogger21.error(`Error reading ${filePath}:`, error40);
|
|
169008
|
+
return JSON.parse(text.slice(start2, end + 1));
|
|
169009
|
+
} catch {
|
|
169010
|
+
return void 0;
|
|
169011
|
+
}
|
|
169012
|
+
}
|
|
169013
|
+
function collectStrings(value, seen, depth = 0) {
|
|
169014
|
+
if (depth > MAX_COLLECT_DEPTH || value === null || value === void 0) {
|
|
169015
|
+
return [];
|
|
169016
|
+
}
|
|
169017
|
+
if (typeof value === "string") {
|
|
169018
|
+
const parsed = tryParseEmbeddedJson(value);
|
|
169019
|
+
if (parsed === void 0) {
|
|
169020
|
+
return [value];
|
|
169240
169021
|
}
|
|
169022
|
+
return [value, ...collectStrings(parsed, seen, depth + 1)];
|
|
169023
|
+
}
|
|
169024
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
169025
|
+
return [String(value)];
|
|
169026
|
+
}
|
|
169027
|
+
if (typeof value !== "object") {
|
|
169028
|
+
return [];
|
|
169029
|
+
}
|
|
169030
|
+
if (seen.has(value)) {
|
|
169241
169031
|
return [];
|
|
169242
169032
|
}
|
|
169033
|
+
seen.add(value);
|
|
169034
|
+
const strings = [];
|
|
169035
|
+
if (value instanceof Error) {
|
|
169036
|
+
strings.push(value.name, value.message);
|
|
169037
|
+
strings.push(...collectStrings(value.cause, seen, depth + 1));
|
|
169038
|
+
}
|
|
169039
|
+
for (const [, nested] of Object.entries(value)) {
|
|
169040
|
+
strings.push(...collectStrings(nested, seen, depth + 1));
|
|
169041
|
+
}
|
|
169042
|
+
return strings;
|
|
169243
169043
|
}
|
|
169244
|
-
|
|
169245
|
-
const
|
|
169246
|
-
|
|
169247
|
-
|
|
169248
|
-
|
|
169249
|
-
|
|
169250
|
-
|
|
169251
|
-
fs17.mkdirSync(dir, { recursive: true });
|
|
169044
|
+
function uniqueNonEmpty(values) {
|
|
169045
|
+
const seen = /* @__PURE__ */ new Set();
|
|
169046
|
+
const result = [];
|
|
169047
|
+
for (const value of values) {
|
|
169048
|
+
const trimmed2 = value.trim();
|
|
169049
|
+
if (!trimmed2 || seen.has(trimmed2)) {
|
|
169050
|
+
continue;
|
|
169252
169051
|
}
|
|
169253
|
-
|
|
169254
|
-
|
|
169052
|
+
seen.add(trimmed2);
|
|
169053
|
+
result.push(trimmed2);
|
|
169054
|
+
}
|
|
169055
|
+
return result;
|
|
169255
169056
|
}
|
|
169256
|
-
function
|
|
169257
|
-
const
|
|
169258
|
-
|
|
169259
|
-
const
|
|
169260
|
-
|
|
169261
|
-
|
|
169057
|
+
function getContextLengthExceededInfo(error40) {
|
|
169058
|
+
const fragments = uniqueNonEmpty(collectStrings(error40, /* @__PURE__ */ new Set()));
|
|
169059
|
+
const message = fragments.join("\n");
|
|
169060
|
+
const isTimeout = TIMEOUT_PATTERNS.some((pattern) => pattern.test(message));
|
|
169061
|
+
const isExceeded = !isTimeout && fragments.some((fragment) => CONTEXT_LENGTH_PATTERNS.some((pattern) => pattern.test(fragment)));
|
|
169062
|
+
const counts = isExceeded ? parseTokenCounts(message) : {};
|
|
169063
|
+
return {
|
|
169064
|
+
isExceeded,
|
|
169065
|
+
message,
|
|
169066
|
+
...counts
|
|
169067
|
+
};
|
|
169068
|
+
}
|
|
169069
|
+
var MAX_COLLECT_DEPTH, TIMEOUT_PATTERNS, CONTEXT_LENGTH_PATTERNS;
|
|
169070
|
+
var init_contextLengthError = __esm({
|
|
169071
|
+
"packages/core/dist/src/utils/contextLengthError.js"() {
|
|
169072
|
+
"use strict";
|
|
169073
|
+
init_esbuild_shims();
|
|
169074
|
+
MAX_COLLECT_DEPTH = 4;
|
|
169075
|
+
TIMEOUT_PATTERNS = [
|
|
169076
|
+
/\bcontext deadline exceeded\b/i,
|
|
169077
|
+
/\bdeadline exceeded\b/i,
|
|
169078
|
+
/\b(?:request|connection|read|context)\s+timed out\b/i,
|
|
169079
|
+
/\b(?:request|connection|read|context)\s+timeout\b/i,
|
|
169080
|
+
/\b(?:timeout|timed out)\s+(?:after|while|during)\b/i
|
|
169081
|
+
];
|
|
169082
|
+
CONTEXT_LENGTH_PATTERNS = [
|
|
169083
|
+
/\bcontext[_\s-]?length[_\s-]?exceeded\b/i,
|
|
169084
|
+
/\bmaximum context length\b/i,
|
|
169085
|
+
/\bprompt\s+(?:is\s+)?too long\b/i,
|
|
169086
|
+
/\binput\s+(?:token\s+)?(?:count\s+|length\s+)?(?:is\s+)?too long\b/i,
|
|
169087
|
+
/\brange of input length should be\b/i,
|
|
169088
|
+
/\btoo many tokens\b/i,
|
|
169089
|
+
/\btokens?\s*>\s*[\d,]+\s*(?:maximum|max|limit)\b/i,
|
|
169090
|
+
/\b(?:input|prompt|messages?|context)\b[^\n]{0,120}\btokens?\b[^\n]{0,120}\bexceed(?:s|ed|ing)?\b/i
|
|
169091
|
+
];
|
|
169092
|
+
__name(parseInteger, "parseInteger");
|
|
169093
|
+
__name(parseTokenCounts, "parseTokenCounts");
|
|
169094
|
+
__name(tryParseEmbeddedJson, "tryParseEmbeddedJson");
|
|
169095
|
+
__name(collectStrings, "collectStrings");
|
|
169096
|
+
__name(uniqueNonEmpty, "uniqueNonEmpty");
|
|
169097
|
+
__name(getContextLengthExceededInfo, "getContextLengthExceededInfo");
|
|
169098
|
+
}
|
|
169099
|
+
});
|
|
169100
|
+
|
|
169101
|
+
// packages/core/dist/src/utils/thoughtUtils.js
|
|
169102
|
+
function parseThought(rawText) {
|
|
169103
|
+
const startIndex = rawText.indexOf(START_DELIMITER);
|
|
169104
|
+
if (startIndex === -1) {
|
|
169105
|
+
return { subject: "", description: rawText };
|
|
169106
|
+
}
|
|
169107
|
+
const endIndex = rawText.indexOf(END_DELIMITER, startIndex + START_DELIMITER.length);
|
|
169108
|
+
if (endIndex === -1) {
|
|
169109
|
+
return { subject: "", description: rawText };
|
|
169262
169110
|
}
|
|
169263
|
-
|
|
169111
|
+
const subject = rawText.substring(startIndex + START_DELIMITER.length, endIndex).trim();
|
|
169112
|
+
const description = (rawText.substring(0, startIndex) + rawText.substring(endIndex + END_DELIMITER.length)).trim();
|
|
169113
|
+
return { subject, description };
|
|
169264
169114
|
}
|
|
169265
|
-
function
|
|
169266
|
-
|
|
169267
|
-
|
|
169268
|
-
|
|
169269
|
-
|
|
169115
|
+
function getThoughtText(response) {
|
|
169116
|
+
if (response.candidates && response.candidates.length > 0) {
|
|
169117
|
+
const candidate = response.candidates[0];
|
|
169118
|
+
if (candidate.content && candidate.content.parts && candidate.content.parts.length > 0) {
|
|
169119
|
+
return candidate.content.parts.filter((part) => part.thought && !isInternalPart(part)).map((part) => part.text ?? "").join("");
|
|
169120
|
+
}
|
|
169270
169121
|
}
|
|
169271
|
-
|
|
169272
|
-
`, "utf8");
|
|
169122
|
+
return null;
|
|
169273
169123
|
}
|
|
169274
|
-
|
|
169275
|
-
|
|
169276
|
-
|
|
169277
|
-
|
|
169278
|
-
|
|
169279
|
-
|
|
169124
|
+
var START_DELIMITER, END_DELIMITER;
|
|
169125
|
+
var init_thoughtUtils = __esm({
|
|
169126
|
+
"packages/core/dist/src/utils/thoughtUtils.js"() {
|
|
169127
|
+
"use strict";
|
|
169128
|
+
init_esbuild_shims();
|
|
169129
|
+
init_partUtils();
|
|
169130
|
+
START_DELIMITER = "**";
|
|
169131
|
+
END_DELIMITER = "**";
|
|
169132
|
+
__name(parseThought, "parseThought");
|
|
169133
|
+
__name(getThoughtText, "getThoughtText");
|
|
169134
|
+
}
|
|
169135
|
+
});
|
|
169136
|
+
|
|
169137
|
+
// packages/core/dist/src/utils/streamStall.js
|
|
169138
|
+
async function* withChunkTimeout(source2, timeoutMs) {
|
|
169139
|
+
while (true) {
|
|
169140
|
+
let timer;
|
|
169141
|
+
const stallPromise = new Promise((_2, reject) => {
|
|
169142
|
+
timer = setTimeout(() => reject(new StreamStallError(timeoutMs)), timeoutMs);
|
|
169280
169143
|
});
|
|
169281
|
-
let
|
|
169282
|
-
|
|
169283
|
-
|
|
169284
|
-
|
|
169144
|
+
let result;
|
|
169145
|
+
try {
|
|
169146
|
+
result = await Promise.race([source2.next(), stallPromise]);
|
|
169147
|
+
clearTimeout(timer);
|
|
169148
|
+
} catch (err3) {
|
|
169149
|
+
clearTimeout(timer);
|
|
169150
|
+
try {
|
|
169151
|
+
void source2.return?.(void 0);
|
|
169152
|
+
} catch {
|
|
169285
169153
|
}
|
|
169154
|
+
throw err3;
|
|
169286
169155
|
}
|
|
169287
|
-
|
|
169288
|
-
|
|
169289
|
-
|
|
169290
|
-
debugLogger21.error(`Error counting lines in ${filePath}:`, error40);
|
|
169291
|
-
}
|
|
169292
|
-
return 0;
|
|
169156
|
+
if (result.done)
|
|
169157
|
+
return;
|
|
169158
|
+
yield result.value;
|
|
169293
169159
|
}
|
|
169294
169160
|
}
|
|
169295
|
-
|
|
169296
|
-
|
|
169297
|
-
|
|
169298
|
-
|
|
169299
|
-
|
|
169300
|
-
|
|
169161
|
+
var StreamStallError;
|
|
169162
|
+
var init_streamStall = __esm({
|
|
169163
|
+
"packages/core/dist/src/utils/streamStall.js"() {
|
|
169164
|
+
"use strict";
|
|
169165
|
+
init_esbuild_shims();
|
|
169166
|
+
StreamStallError = class extends Error {
|
|
169167
|
+
static {
|
|
169168
|
+
__name(this, "StreamStallError");
|
|
169169
|
+
}
|
|
169170
|
+
timeoutMs;
|
|
169171
|
+
constructor(timeoutMs) {
|
|
169172
|
+
super(`Stream stalled: no data received for ${timeoutMs / 1e3}s. The model connection may have dropped \u2014 please try again.`);
|
|
169173
|
+
this.name = "StreamStallError";
|
|
169174
|
+
this.timeoutMs = timeoutMs;
|
|
169175
|
+
}
|
|
169176
|
+
};
|
|
169177
|
+
__name(withChunkTimeout, "withChunkTimeout");
|
|
169301
169178
|
}
|
|
169179
|
+
});
|
|
169180
|
+
|
|
169181
|
+
// packages/core/dist/src/core/turn.js
|
|
169182
|
+
function getCitations(resp) {
|
|
169183
|
+
return (resp.candidates?.[0]?.citationMetadata?.citations ?? []).filter((citation) => citation.uri !== void 0).map((citation) => {
|
|
169184
|
+
if (citation.title) {
|
|
169185
|
+
return `(${citation.title}) ${citation.uri}`;
|
|
169186
|
+
}
|
|
169187
|
+
return citation.uri;
|
|
169188
|
+
});
|
|
169302
169189
|
}
|
|
169303
|
-
var
|
|
169304
|
-
var
|
|
169305
|
-
"packages/core/dist/src/
|
|
169190
|
+
var STREAM_STALL_TIMEOUT_MS, GeminiEventType, CompressionStatus, Turn;
|
|
169191
|
+
var init_turn = __esm({
|
|
169192
|
+
"packages/core/dist/src/core/turn.js"() {
|
|
169306
169193
|
"use strict";
|
|
169307
169194
|
init_esbuild_shims();
|
|
169308
|
-
|
|
169309
|
-
|
|
169310
|
-
|
|
169311
|
-
|
|
169312
|
-
|
|
169313
|
-
|
|
169314
|
-
|
|
169315
|
-
|
|
169316
|
-
|
|
169317
|
-
|
|
169318
|
-
|
|
169319
|
-
|
|
169195
|
+
init_node();
|
|
169196
|
+
init_partUtils();
|
|
169197
|
+
init_errorReporting();
|
|
169198
|
+
init_errors();
|
|
169199
|
+
init_thoughtUtils();
|
|
169200
|
+
init_streamStall();
|
|
169201
|
+
STREAM_STALL_TIMEOUT_MS = parseInt(process.env["PROTO_STREAM_STALL_TIMEOUT_MS"] ?? "300000", 10);
|
|
169202
|
+
(function(GeminiEventType2) {
|
|
169203
|
+
GeminiEventType2["Content"] = "content";
|
|
169204
|
+
GeminiEventType2["ToolCallRequest"] = "tool_call_request";
|
|
169205
|
+
GeminiEventType2["ToolCallResponse"] = "tool_call_response";
|
|
169206
|
+
GeminiEventType2["ToolCallConfirmation"] = "tool_call_confirmation";
|
|
169207
|
+
GeminiEventType2["UserCancelled"] = "user_cancelled";
|
|
169208
|
+
GeminiEventType2["Error"] = "error";
|
|
169209
|
+
GeminiEventType2["ChatCompressed"] = "chat_compressed";
|
|
169210
|
+
GeminiEventType2["Thought"] = "thought";
|
|
169211
|
+
GeminiEventType2["MaxSessionTurns"] = "max_session_turns";
|
|
169212
|
+
GeminiEventType2["SessionTokenLimitExceeded"] = "session_token_limit_exceeded";
|
|
169213
|
+
GeminiEventType2["Finished"] = "finished";
|
|
169214
|
+
GeminiEventType2["LoopDetected"] = "loop_detected";
|
|
169215
|
+
GeminiEventType2["Citation"] = "citation";
|
|
169216
|
+
GeminiEventType2["Retry"] = "retry";
|
|
169217
|
+
GeminiEventType2["HookSystemMessage"] = "hook_system_message";
|
|
169218
|
+
})(GeminiEventType || (GeminiEventType = {}));
|
|
169219
|
+
(function(CompressionStatus2) {
|
|
169220
|
+
CompressionStatus2[CompressionStatus2["COMPRESSED"] = 1] = "COMPRESSED";
|
|
169221
|
+
CompressionStatus2[CompressionStatus2["COMPRESSION_FAILED_INFLATED_TOKEN_COUNT"] = 2] = "COMPRESSION_FAILED_INFLATED_TOKEN_COUNT";
|
|
169222
|
+
CompressionStatus2[CompressionStatus2["COMPRESSION_FAILED_TOKEN_COUNT_ERROR"] = 3] = "COMPRESSION_FAILED_TOKEN_COUNT_ERROR";
|
|
169223
|
+
CompressionStatus2[CompressionStatus2["COMPRESSION_FAILED_EMPTY_SUMMARY"] = 4] = "COMPRESSION_FAILED_EMPTY_SUMMARY";
|
|
169224
|
+
CompressionStatus2[CompressionStatus2["NOOP"] = 5] = "NOOP";
|
|
169225
|
+
})(CompressionStatus || (CompressionStatus = {}));
|
|
169226
|
+
Turn = class {
|
|
169227
|
+
static {
|
|
169228
|
+
__name(this, "Turn");
|
|
169229
|
+
}
|
|
169230
|
+
chat;
|
|
169231
|
+
prompt_id;
|
|
169232
|
+
pendingToolCalls = [];
|
|
169233
|
+
debugResponses = [];
|
|
169234
|
+
pendingCitations = /* @__PURE__ */ new Set();
|
|
169235
|
+
finishReason = void 0;
|
|
169236
|
+
currentResponseId;
|
|
169237
|
+
constructor(chat, prompt_id) {
|
|
169238
|
+
this.chat = chat;
|
|
169239
|
+
this.prompt_id = prompt_id;
|
|
169240
|
+
}
|
|
169241
|
+
// The run method yields simpler events suitable for server logic
|
|
169242
|
+
async *run(model, req, signal) {
|
|
169243
|
+
try {
|
|
169244
|
+
const rawStream = await this.chat.sendMessageStream(model, {
|
|
169245
|
+
message: req,
|
|
169246
|
+
config: {
|
|
169247
|
+
abortSignal: signal
|
|
169248
|
+
}
|
|
169249
|
+
}, this.prompt_id);
|
|
169250
|
+
const responseStream = withChunkTimeout(rawStream, STREAM_STALL_TIMEOUT_MS);
|
|
169251
|
+
for await (const streamEvent of responseStream) {
|
|
169252
|
+
if (signal?.aborted) {
|
|
169253
|
+
yield { type: GeminiEventType.UserCancelled };
|
|
169254
|
+
return;
|
|
169255
|
+
}
|
|
169256
|
+
if (streamEvent.type === "retry") {
|
|
169257
|
+
yield {
|
|
169258
|
+
type: GeminiEventType.Retry,
|
|
169259
|
+
retryInfo: streamEvent.retryInfo
|
|
169260
|
+
};
|
|
169261
|
+
continue;
|
|
169262
|
+
}
|
|
169263
|
+
const resp = streamEvent.value;
|
|
169264
|
+
if (!resp)
|
|
169265
|
+
continue;
|
|
169266
|
+
this.debugResponses.push(resp);
|
|
169267
|
+
if (resp.responseId) {
|
|
169268
|
+
this.currentResponseId = resp.responseId;
|
|
169269
|
+
}
|
|
169270
|
+
const thoughtText = getThoughtText(resp);
|
|
169271
|
+
if (thoughtText) {
|
|
169272
|
+
yield {
|
|
169273
|
+
type: GeminiEventType.Thought,
|
|
169274
|
+
value: parseThought(thoughtText)
|
|
169275
|
+
};
|
|
169276
|
+
}
|
|
169277
|
+
const text = getResponseText(resp);
|
|
169278
|
+
if (text) {
|
|
169279
|
+
yield { type: GeminiEventType.Content, value: text };
|
|
169280
|
+
}
|
|
169281
|
+
const functionCalls = resp.functionCalls ?? [];
|
|
169282
|
+
for (const fnCall of functionCalls) {
|
|
169283
|
+
const event = this.handlePendingFunctionCall(fnCall);
|
|
169284
|
+
if (event) {
|
|
169285
|
+
yield event;
|
|
169286
|
+
}
|
|
169287
|
+
}
|
|
169288
|
+
for (const citation of getCitations(resp)) {
|
|
169289
|
+
this.pendingCitations.add(citation);
|
|
169290
|
+
}
|
|
169291
|
+
const finishReason = resp.candidates?.[0]?.finishReason;
|
|
169292
|
+
if (finishReason) {
|
|
169293
|
+
if (finishReason === FinishReason.MAX_TOKENS) {
|
|
169294
|
+
for (const tc of this.pendingToolCalls) {
|
|
169295
|
+
tc.wasOutputTruncated = true;
|
|
169296
|
+
}
|
|
169297
|
+
}
|
|
169298
|
+
if (this.pendingCitations.size > 0) {
|
|
169299
|
+
yield {
|
|
169300
|
+
type: GeminiEventType.Citation,
|
|
169301
|
+
value: `Citations:
|
|
169302
|
+
${[...this.pendingCitations].sort().join("\n")}`
|
|
169303
|
+
};
|
|
169304
|
+
this.pendingCitations.clear();
|
|
169305
|
+
}
|
|
169306
|
+
this.finishReason = finishReason;
|
|
169307
|
+
yield {
|
|
169308
|
+
type: GeminiEventType.Finished,
|
|
169309
|
+
value: {
|
|
169310
|
+
reason: finishReason,
|
|
169311
|
+
usageMetadata: resp.usageMetadata
|
|
169312
|
+
}
|
|
169313
|
+
};
|
|
169314
|
+
}
|
|
169315
|
+
}
|
|
169316
|
+
} catch (e4) {
|
|
169317
|
+
if (signal.aborted) {
|
|
169318
|
+
yield { type: GeminiEventType.UserCancelled };
|
|
169319
|
+
return;
|
|
169320
|
+
}
|
|
169321
|
+
if (e4 instanceof StreamStallError) {
|
|
169322
|
+
yield {
|
|
169323
|
+
type: GeminiEventType.Error,
|
|
169324
|
+
value: {
|
|
169325
|
+
error: {
|
|
169326
|
+
message: e4.message,
|
|
169327
|
+
status: void 0
|
|
169328
|
+
}
|
|
169329
|
+
}
|
|
169330
|
+
};
|
|
169331
|
+
return;
|
|
169332
|
+
}
|
|
169333
|
+
const error40 = toFriendlyError(e4);
|
|
169334
|
+
if (error40 instanceof UnauthorizedError) {
|
|
169335
|
+
throw error40;
|
|
169336
|
+
}
|
|
169337
|
+
const contextForReport = [...this.chat.getHistory(
|
|
169338
|
+
/*curated*/
|
|
169339
|
+
true
|
|
169340
|
+
), req];
|
|
169341
|
+
await reportError2(error40, "Error when talking to API", contextForReport, "Turn.run-sendMessageStream");
|
|
169342
|
+
const status = typeof error40 === "object" && error40 !== null && "status" in error40 && typeof error40.status === "number" ? error40.status : void 0;
|
|
169343
|
+
const structuredError = {
|
|
169344
|
+
message: getErrorMessage(error40),
|
|
169345
|
+
status
|
|
169346
|
+
};
|
|
169347
|
+
await this.chat.maybeIncludeSchemaDepthContext(structuredError);
|
|
169348
|
+
yield { type: GeminiEventType.Error, value: { error: structuredError } };
|
|
169349
|
+
return;
|
|
169350
|
+
}
|
|
169351
|
+
}
|
|
169352
|
+
handlePendingFunctionCall(fnCall) {
|
|
169353
|
+
const callId = fnCall.id ?? `${fnCall.name}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
169354
|
+
const name4 = fnCall.name || "undefined_tool_name";
|
|
169355
|
+
const args2 = fnCall.args || {};
|
|
169356
|
+
const toolCallRequest = {
|
|
169357
|
+
callId,
|
|
169358
|
+
name: name4,
|
|
169359
|
+
args: args2,
|
|
169360
|
+
isClientInitiated: false,
|
|
169361
|
+
prompt_id: this.prompt_id,
|
|
169362
|
+
response_id: this.currentResponseId
|
|
169363
|
+
};
|
|
169364
|
+
this.pendingToolCalls.push(toolCallRequest);
|
|
169365
|
+
return { type: GeminiEventType.ToolCallRequest, value: toolCallRequest };
|
|
169366
|
+
}
|
|
169367
|
+
getDebugResponses() {
|
|
169368
|
+
return this.debugResponses;
|
|
169369
|
+
}
|
|
169370
|
+
};
|
|
169371
|
+
__name(getCitations, "getCitations");
|
|
169320
169372
|
}
|
|
169321
169373
|
});
|
|
169322
169374
|
|
|
169323
169375
|
// packages/core/dist/src/utils/gitUtils.js
|
|
169324
|
-
import * as
|
|
169325
|
-
import * as
|
|
169376
|
+
import * as fs17 from "node:fs";
|
|
169377
|
+
import * as path16 from "node:path";
|
|
169326
169378
|
import { execSync as execSync2 } from "node:child_process";
|
|
169327
169379
|
function isGitRepository(directory) {
|
|
169328
169380
|
try {
|
|
169329
|
-
let currentDir =
|
|
169381
|
+
let currentDir = path16.resolve(directory);
|
|
169330
169382
|
while (true) {
|
|
169331
|
-
const gitDir =
|
|
169332
|
-
if (
|
|
169383
|
+
const gitDir = path16.join(currentDir, ".git");
|
|
169384
|
+
if (fs17.existsSync(gitDir)) {
|
|
169333
169385
|
return true;
|
|
169334
169386
|
}
|
|
169335
|
-
const parentDir =
|
|
169387
|
+
const parentDir = path16.dirname(currentDir);
|
|
169336
169388
|
if (parentDir === currentDir) {
|
|
169337
169389
|
break;
|
|
169338
169390
|
}
|
|
@@ -169345,13 +169397,13 @@ function isGitRepository(directory) {
|
|
|
169345
169397
|
}
|
|
169346
169398
|
function findGitRoot(directory) {
|
|
169347
169399
|
try {
|
|
169348
|
-
let currentDir =
|
|
169400
|
+
let currentDir = path16.resolve(directory);
|
|
169349
169401
|
while (true) {
|
|
169350
|
-
const gitDir =
|
|
169351
|
-
if (
|
|
169402
|
+
const gitDir = path16.join(currentDir, ".git");
|
|
169403
|
+
if (fs17.existsSync(gitDir)) {
|
|
169352
169404
|
return currentDir;
|
|
169353
169405
|
}
|
|
169354
|
-
const parentDir =
|
|
169406
|
+
const parentDir = path16.dirname(currentDir);
|
|
169355
169407
|
if (parentDir === currentDir) {
|
|
169356
169408
|
break;
|
|
169357
169409
|
}
|
|
@@ -169410,985 +169462,102 @@ var init_gitUtils = __esm({
|
|
|
169410
169462
|
}
|
|
169411
169463
|
const gitRoot = findGitRoot(cwd6);
|
|
169412
169464
|
if (gitRoot) {
|
|
169413
|
-
return
|
|
169465
|
+
return path16.basename(gitRoot);
|
|
169414
169466
|
}
|
|
169415
169467
|
return void 0;
|
|
169416
169468
|
}, "getGitRepoName");
|
|
169417
169469
|
}
|
|
169418
169470
|
});
|
|
169419
169471
|
|
|
169420
|
-
// packages/core/dist/src/
|
|
169421
|
-
import
|
|
169422
|
-
import
|
|
169423
|
-
import
|
|
169424
|
-
|
|
169425
|
-
|
|
169426
|
-
|
|
169427
|
-
|
|
169428
|
-
|
|
169429
|
-
|
|
169430
|
-
|
|
169431
|
-
|
|
169432
|
-
|
|
169433
|
-
|
|
169434
|
-
|
|
169435
|
-
|
|
169436
|
-
|
|
169437
|
-
|
|
169438
|
-
|
|
169439
|
-
|
|
169440
|
-
|
|
169441
|
-
|
|
169442
|
-
/** In-memory cache of the current session's custom title (for re-append on exit) */
|
|
169443
|
-
currentCustomTitle;
|
|
169444
|
-
constructor(config2) {
|
|
169445
|
-
this.config = config2;
|
|
169446
|
-
this.lastRecordUuid = config2.getResumedSessionData()?.lastCompletedUuid ?? null;
|
|
169447
|
-
if (config2.getResumedSessionData()) {
|
|
169448
|
-
try {
|
|
169449
|
-
const sessionService = config2.getSessionService();
|
|
169450
|
-
this.currentCustomTitle = sessionService.getSessionTitle(config2.getSessionId());
|
|
169451
|
-
this.finalize();
|
|
169452
|
-
} catch {
|
|
169453
|
-
}
|
|
169454
|
-
}
|
|
169455
|
-
}
|
|
169456
|
-
/**
|
|
169457
|
-
* Returns the session ID.
|
|
169458
|
-
* @returns The session ID.
|
|
169459
|
-
*/
|
|
169460
|
-
getSessionId() {
|
|
169461
|
-
return this.config.getSessionId();
|
|
169462
|
-
}
|
|
169463
|
-
/**
|
|
169464
|
-
* Ensures the chats directory exists, creating it if it doesn't exist.
|
|
169465
|
-
* @returns The path to the chats directory.
|
|
169466
|
-
* @throws Error if the directory cannot be created.
|
|
169467
|
-
*/
|
|
169468
|
-
ensureChatsDir() {
|
|
169469
|
-
const projectDir = this.config.storage.getProjectDir();
|
|
169470
|
-
const chatsDir = path18.join(projectDir, "chats");
|
|
169471
|
-
try {
|
|
169472
|
-
fs19.mkdirSync(chatsDir, { recursive: true });
|
|
169473
|
-
} catch {
|
|
169474
|
-
}
|
|
169475
|
-
return chatsDir;
|
|
169476
|
-
}
|
|
169477
|
-
/**
|
|
169478
|
-
* Ensures the conversation file exists, creating it if it doesn't exist.
|
|
169479
|
-
* Uses atomic file creation to avoid race conditions.
|
|
169480
|
-
* @returns The path to the conversation file.
|
|
169481
|
-
* @throws Error if the file cannot be created or accessed.
|
|
169482
|
-
*/
|
|
169483
|
-
ensureConversationFile() {
|
|
169484
|
-
const chatsDir = this.ensureChatsDir();
|
|
169485
|
-
const sessionId = this.getSessionId();
|
|
169486
|
-
const safeFilename = `${sessionId}.jsonl`;
|
|
169487
|
-
const conversationFile = path18.join(chatsDir, safeFilename);
|
|
169488
|
-
if (fs19.existsSync(conversationFile)) {
|
|
169489
|
-
return conversationFile;
|
|
169490
|
-
}
|
|
169491
|
-
try {
|
|
169492
|
-
fs19.writeFileSync(conversationFile, "", { flag: "wx", encoding: "utf8" });
|
|
169493
|
-
} catch (error40) {
|
|
169494
|
-
const nodeError = error40;
|
|
169495
|
-
if (nodeError.code !== "EEXIST") {
|
|
169496
|
-
const message = error40 instanceof Error ? error40.message : String(error40);
|
|
169497
|
-
throw new Error(`Failed to create conversation file at ${conversationFile}: ${message}`);
|
|
169498
|
-
}
|
|
169499
|
-
}
|
|
169500
|
-
return conversationFile;
|
|
169501
|
-
}
|
|
169502
|
-
/**
|
|
169503
|
-
* Creates base fields for a ChatRecord.
|
|
169504
|
-
*/
|
|
169505
|
-
createBaseRecord(type) {
|
|
169506
|
-
return {
|
|
169507
|
-
uuid: randomUUID2(),
|
|
169508
|
-
parentUuid: this.lastRecordUuid,
|
|
169509
|
-
sessionId: this.getSessionId(),
|
|
169510
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
169511
|
-
type,
|
|
169512
|
-
cwd: this.config.getProjectRoot(),
|
|
169513
|
-
version: this.config.getCliVersion() || "unknown",
|
|
169514
|
-
gitBranch: getGitBranch(this.config.getProjectRoot())
|
|
169515
|
-
};
|
|
169516
|
-
}
|
|
169517
|
-
/**
|
|
169518
|
-
* Appends a record to the session file and updates lastRecordUuid.
|
|
169519
|
-
*/
|
|
169520
|
-
appendRecord(record2) {
|
|
169521
|
-
try {
|
|
169522
|
-
const conversationFile = this.ensureConversationFile();
|
|
169523
|
-
writeLineSync(conversationFile, record2);
|
|
169524
|
-
this.lastRecordUuid = record2.uuid;
|
|
169525
|
-
} catch (error40) {
|
|
169526
|
-
debugLogger22.error("Error appending record:", error40);
|
|
169527
|
-
throw error40;
|
|
169528
|
-
}
|
|
169529
|
-
}
|
|
169530
|
-
/**
|
|
169531
|
-
* Records a user message.
|
|
169532
|
-
* Writes immediately to disk.
|
|
169533
|
-
*
|
|
169534
|
-
* @param message The raw PartListUnion object as used with the API
|
|
169535
|
-
*/
|
|
169536
|
-
recordUserMessage(message) {
|
|
169537
|
-
try {
|
|
169538
|
-
const record2 = {
|
|
169539
|
-
...this.createBaseRecord("user"),
|
|
169540
|
-
message: createUserContent(message)
|
|
169541
|
-
};
|
|
169542
|
-
this.appendRecord(record2);
|
|
169543
|
-
} catch (error40) {
|
|
169544
|
-
debugLogger22.error("Error saving user message:", error40);
|
|
169545
|
-
}
|
|
169546
|
-
}
|
|
169547
|
-
/**
|
|
169548
|
-
* Records an assistant turn with all available data.
|
|
169549
|
-
* Writes immediately to disk.
|
|
169550
|
-
*
|
|
169551
|
-
* @param data.message The raw PartListUnion object from the model response
|
|
169552
|
-
* @param data.model The model name
|
|
169553
|
-
* @param data.tokens Token usage statistics
|
|
169554
|
-
* @param data.contextWindowSize Context window size of the model
|
|
169555
|
-
* @param data.toolCallsMetadata Enriched tool call info for UI recovery
|
|
169556
|
-
*/
|
|
169557
|
-
recordAssistantTurn(data) {
|
|
169558
|
-
try {
|
|
169559
|
-
const record2 = {
|
|
169560
|
-
...this.createBaseRecord("assistant"),
|
|
169561
|
-
model: data.model
|
|
169562
|
-
};
|
|
169563
|
-
if (data.message !== void 0) {
|
|
169564
|
-
record2.message = createModelContent(data.message);
|
|
169565
|
-
}
|
|
169566
|
-
if (data.tokens) {
|
|
169567
|
-
record2.usageMetadata = data.tokens;
|
|
169568
|
-
}
|
|
169569
|
-
if (data.contextWindowSize !== void 0) {
|
|
169570
|
-
record2.contextWindowSize = data.contextWindowSize;
|
|
169571
|
-
}
|
|
169572
|
-
this.appendRecord(record2);
|
|
169573
|
-
} catch (error40) {
|
|
169574
|
-
debugLogger22.error("Error saving assistant turn:", error40);
|
|
169575
|
-
}
|
|
169576
|
-
}
|
|
169577
|
-
/**
|
|
169578
|
-
* Records tool results (function responses) sent back to the model.
|
|
169579
|
-
* Writes immediately to disk.
|
|
169580
|
-
*
|
|
169581
|
-
* @param message The raw PartListUnion object with functionResponse parts
|
|
169582
|
-
* @param toolCallResult Optional tool call result info for UI recovery
|
|
169583
|
-
*/
|
|
169584
|
-
recordToolResult(message, toolCallResult) {
|
|
169585
|
-
try {
|
|
169586
|
-
const record2 = {
|
|
169587
|
-
...this.createBaseRecord("tool_result"),
|
|
169588
|
-
message: createUserContent(message)
|
|
169589
|
-
};
|
|
169590
|
-
if (toolCallResult) {
|
|
169591
|
-
if (typeof toolCallResult.resultDisplay === "object" && toolCallResult.resultDisplay !== null && "type" in toolCallResult.resultDisplay && toolCallResult.resultDisplay.type === "task_execution") {
|
|
169592
|
-
const taskResult = toolCallResult.resultDisplay;
|
|
169593
|
-
record2.toolCallResult = {
|
|
169594
|
-
...toolCallResult,
|
|
169595
|
-
resultDisplay: {
|
|
169596
|
-
...taskResult,
|
|
169597
|
-
toolCalls: []
|
|
169598
|
-
}
|
|
169599
|
-
};
|
|
169600
|
-
} else {
|
|
169601
|
-
record2.toolCallResult = toolCallResult;
|
|
169602
|
-
}
|
|
169603
|
-
}
|
|
169604
|
-
this.appendRecord(record2);
|
|
169605
|
-
} catch (error40) {
|
|
169606
|
-
debugLogger22.error("Error saving tool result:", error40);
|
|
169607
|
-
}
|
|
169608
|
-
}
|
|
169609
|
-
/**
|
|
169610
|
-
* Records a slash command invocation as a system record. This keeps the model
|
|
169611
|
-
* history clean while allowing resume to replay UI output for commands like
|
|
169612
|
-
* /about.
|
|
169613
|
-
*/
|
|
169614
|
-
recordSlashCommand(payload) {
|
|
169615
|
-
try {
|
|
169616
|
-
const record2 = {
|
|
169617
|
-
...this.createBaseRecord("system"),
|
|
169618
|
-
type: "system",
|
|
169619
|
-
subtype: "slash_command",
|
|
169620
|
-
systemPayload: payload
|
|
169621
|
-
};
|
|
169622
|
-
this.appendRecord(record2);
|
|
169623
|
-
} catch (error40) {
|
|
169624
|
-
debugLogger22.error("Error saving slash command record:", error40);
|
|
169625
|
-
}
|
|
169626
|
-
}
|
|
169627
|
-
/**
|
|
169628
|
-
* Records a chat compression checkpoint as a system record. This keeps the UI
|
|
169629
|
-
* history immutable while allowing resume/continue flows to reconstruct the
|
|
169630
|
-
* compressed model-facing history from the stored snapshot.
|
|
169631
|
-
*/
|
|
169632
|
-
recordChatCompression(payload) {
|
|
169633
|
-
try {
|
|
169634
|
-
const record2 = {
|
|
169635
|
-
...this.createBaseRecord("system"),
|
|
169636
|
-
type: "system",
|
|
169637
|
-
subtype: "chat_compression",
|
|
169638
|
-
systemPayload: payload
|
|
169639
|
-
};
|
|
169640
|
-
this.appendRecord(record2);
|
|
169641
|
-
} catch (error40) {
|
|
169642
|
-
debugLogger22.error("Error saving chat compression record:", error40);
|
|
169643
|
-
}
|
|
169644
|
-
}
|
|
169645
|
-
/**
|
|
169646
|
-
* Records a UI telemetry event for replaying metrics on resume.
|
|
169647
|
-
*/
|
|
169648
|
-
recordUiTelemetryEvent(uiEvent) {
|
|
169649
|
-
try {
|
|
169650
|
-
const record2 = {
|
|
169651
|
-
...this.createBaseRecord("system"),
|
|
169652
|
-
type: "system",
|
|
169653
|
-
subtype: "ui_telemetry",
|
|
169654
|
-
systemPayload: { uiEvent }
|
|
169655
|
-
};
|
|
169656
|
-
this.appendRecord(record2);
|
|
169657
|
-
} catch (error40) {
|
|
169658
|
-
debugLogger22.error("Error saving ui telemetry record:", error40);
|
|
169659
|
-
}
|
|
169660
|
-
}
|
|
169661
|
-
/**
|
|
169662
|
-
* Records a custom title for the session (set via /rename).
|
|
169663
|
-
* Appended as a system record so it persists with the session data.
|
|
169664
|
-
* Also caches the title in memory for re-append on shutdown.
|
|
169665
|
-
*
|
|
169666
|
-
* @returns true if the record was written successfully, false on I/O error.
|
|
169667
|
-
*/
|
|
169668
|
-
recordCustomTitle(customTitle) {
|
|
169669
|
-
try {
|
|
169670
|
-
const record2 = {
|
|
169671
|
-
...this.createBaseRecord("system"),
|
|
169672
|
-
type: "system",
|
|
169673
|
-
subtype: "custom_title",
|
|
169674
|
-
systemPayload: { customTitle }
|
|
169675
|
-
};
|
|
169676
|
-
this.appendRecord(record2);
|
|
169677
|
-
this.currentCustomTitle = customTitle;
|
|
169678
|
-
return true;
|
|
169679
|
-
} catch (error40) {
|
|
169680
|
-
debugLogger22.error("Error saving custom title record:", error40);
|
|
169681
|
-
return false;
|
|
169682
|
-
}
|
|
169683
|
-
}
|
|
169684
|
-
/**
|
|
169685
|
-
* Finalizes the current session by re-appending cached metadata to EOF.
|
|
169686
|
-
*
|
|
169687
|
-
* Call this whenever leaving the current session — whether switching to
|
|
169688
|
-
* another session, shutting down the process, or any other transition.
|
|
169689
|
-
* This single entry point replaces scattered re-append calls and ensures
|
|
169690
|
-
* the custom_title record stays within the last 64KB tail window that
|
|
169691
|
-
* readSessionTitleFromFile() scans.
|
|
169692
|
-
*
|
|
169693
|
-
* Best-effort: errors are logged but never thrown.
|
|
169694
|
-
*/
|
|
169695
|
-
finalize() {
|
|
169696
|
-
if (!this.currentCustomTitle) {
|
|
169697
|
-
return;
|
|
169698
|
-
}
|
|
169699
|
-
try {
|
|
169700
|
-
const record2 = {
|
|
169701
|
-
...this.createBaseRecord("system"),
|
|
169702
|
-
type: "system",
|
|
169703
|
-
subtype: "custom_title",
|
|
169704
|
-
systemPayload: { customTitle: this.currentCustomTitle }
|
|
169705
|
-
};
|
|
169706
|
-
this.appendRecord(record2);
|
|
169707
|
-
} catch (error40) {
|
|
169708
|
-
debugLogger22.error("Error finalizing session metadata:", error40);
|
|
169709
|
-
}
|
|
169710
|
-
}
|
|
169711
|
-
/**
|
|
169712
|
-
* Records @-command metadata as a system record for UI reconstruction.
|
|
169713
|
-
*/
|
|
169714
|
-
recordAtCommand(payload) {
|
|
169715
|
-
try {
|
|
169716
|
-
const record2 = {
|
|
169717
|
-
...this.createBaseRecord("system"),
|
|
169718
|
-
type: "system",
|
|
169719
|
-
subtype: "at_command",
|
|
169720
|
-
systemPayload: payload
|
|
169721
|
-
};
|
|
169722
|
-
this.appendRecord(record2);
|
|
169723
|
-
} catch (error40) {
|
|
169724
|
-
debugLogger22.error("Error saving @-command record:", error40);
|
|
169725
|
-
}
|
|
169726
|
-
}
|
|
169727
|
-
};
|
|
169728
|
-
}
|
|
169729
|
-
});
|
|
169730
|
-
|
|
169731
|
-
// packages/core/dist/src/core/geminiChat.js
|
|
169732
|
-
function isValidResponse2(response) {
|
|
169733
|
-
if (response.usageMetadata) {
|
|
169734
|
-
return true;
|
|
169472
|
+
// packages/core/dist/src/core/prompts.js
|
|
169473
|
+
import path17 from "node:path";
|
|
169474
|
+
import fs18 from "node:fs";
|
|
169475
|
+
import os6 from "node:os";
|
|
169476
|
+
import { execSync as execSync3 } from "node:child_process";
|
|
169477
|
+
import process3 from "node:process";
|
|
169478
|
+
function assemblePromptSections(sections) {
|
|
169479
|
+
const stable = sections.filter((s5) => s5.volatility === "stable" && s5.content);
|
|
169480
|
+
const workspace = sections.filter((s5) => s5.volatility === "workspace" && s5.content);
|
|
169481
|
+
const run3 = sections.filter((s5) => s5.volatility === "run" && s5.content);
|
|
169482
|
+
const stablePart = stable.map((s5) => s5.content).join("\n\n");
|
|
169483
|
+
const nonStable = [...workspace, ...run3].map((s5) => s5.content).join("\n\n");
|
|
169484
|
+
if (!stablePart)
|
|
169485
|
+
return nonStable;
|
|
169486
|
+
if (!nonStable)
|
|
169487
|
+
return stablePart;
|
|
169488
|
+
return `${stablePart}${CACHE_BOUNDARY_SENTINEL}${nonStable}`;
|
|
169489
|
+
}
|
|
169490
|
+
function resolvePathFromEnv(envVar) {
|
|
169491
|
+
const trimmedEnvVar = envVar?.trim();
|
|
169492
|
+
if (!trimmedEnvVar) {
|
|
169493
|
+
return { isSwitch: false, value: null, isDisabled: false };
|
|
169735
169494
|
}
|
|
169736
|
-
|
|
169737
|
-
|
|
169495
|
+
const lowerEnvVar = trimmedEnvVar.toLowerCase();
|
|
169496
|
+
if (["0", "false", "1", "true"].includes(lowerEnvVar)) {
|
|
169497
|
+
const isDisabled = ["0", "false"].includes(lowerEnvVar);
|
|
169498
|
+
return { isSwitch: true, value: lowerEnvVar, isDisabled };
|
|
169738
169499
|
}
|
|
169739
|
-
|
|
169740
|
-
|
|
169500
|
+
let customPath = trimmedEnvVar;
|
|
169501
|
+
if (customPath.startsWith("~/") || customPath === "~") {
|
|
169502
|
+
try {
|
|
169503
|
+
const home = os6.homedir();
|
|
169504
|
+
if (customPath === "~") {
|
|
169505
|
+
customPath = home;
|
|
169506
|
+
} else {
|
|
169507
|
+
customPath = path17.join(home, customPath.slice(2));
|
|
169508
|
+
}
|
|
169509
|
+
} catch (error40) {
|
|
169510
|
+
debugLogger21.warn(`Could not resolve home directory for path: ${trimmedEnvVar}`, error40);
|
|
169511
|
+
return { isSwitch: false, value: null, isDisabled: false };
|
|
169512
|
+
}
|
|
169741
169513
|
}
|
|
169742
|
-
|
|
169743
|
-
|
|
169744
|
-
|
|
169745
|
-
|
|
169746
|
-
|
|
169747
|
-
// any of these but we don't trust them so check anyways.
|
|
169748
|
-
!part.functionCall && !part.functionResponse && !part.inlineData && !part.fileData;
|
|
169514
|
+
return {
|
|
169515
|
+
isSwitch: false,
|
|
169516
|
+
value: path17.resolve(customPath),
|
|
169517
|
+
isDisabled: false
|
|
169518
|
+
};
|
|
169749
169519
|
}
|
|
169750
|
-
function
|
|
169751
|
-
|
|
169752
|
-
|
|
169753
|
-
|
|
169754
|
-
|
|
169755
|
-
|
|
169756
|
-
|
|
169757
|
-
|
|
169758
|
-
|
|
169759
|
-
|
|
169760
|
-
}
|
|
169520
|
+
function getCustomSystemPrompt(customInstruction, userMemory, appendInstruction) {
|
|
169521
|
+
let instructionText = "";
|
|
169522
|
+
if (typeof customInstruction === "string") {
|
|
169523
|
+
instructionText = customInstruction;
|
|
169524
|
+
} else if (Array.isArray(customInstruction)) {
|
|
169525
|
+
instructionText = customInstruction.map((part) => typeof part === "string" ? part : part.text || "").join("");
|
|
169526
|
+
} else if (customInstruction && "parts" in customInstruction) {
|
|
169527
|
+
instructionText = customInstruction.parts?.map((part) => typeof part === "string" ? part : part.text || "").join("") || "";
|
|
169528
|
+
} else if (customInstruction && "text" in customInstruction) {
|
|
169529
|
+
instructionText = customInstruction.text || "";
|
|
169761
169530
|
}
|
|
169762
|
-
|
|
169531
|
+
const memorySuffix = buildSystemPromptSuffix(userMemory);
|
|
169532
|
+
return `${instructionText}${memorySuffix}${buildSystemPromptSuffix(appendInstruction)}`;
|
|
169763
169533
|
}
|
|
169764
|
-
function
|
|
169765
|
-
const
|
|
169766
|
-
return
|
|
169534
|
+
function buildSystemPromptSuffix(text) {
|
|
169535
|
+
const trimmed2 = text?.trim();
|
|
169536
|
+
return trimmed2 ? `
|
|
169537
|
+
|
|
169538
|
+
---
|
|
169539
|
+
|
|
169540
|
+
${trimmed2}` : "";
|
|
169767
169541
|
}
|
|
169768
|
-
function
|
|
169769
|
-
|
|
169770
|
-
|
|
169771
|
-
|
|
169542
|
+
function getCoreSystemPrompt(userMemory, model, appendInstruction, interactive = false) {
|
|
169543
|
+
let systemMdEnabled = false;
|
|
169544
|
+
let systemMdPath = path17.resolve(path17.join(QWEN_CONFIG_DIR, "system.md"));
|
|
169545
|
+
const systemMdResolution = resolvePathFromEnv(process3.env["QWEN_SYSTEM_MD"]);
|
|
169546
|
+
if (systemMdResolution.value && !systemMdResolution.isDisabled) {
|
|
169547
|
+
systemMdEnabled = true;
|
|
169548
|
+
if (!systemMdResolution.isSwitch) {
|
|
169549
|
+
systemMdPath = systemMdResolution.value;
|
|
169550
|
+
}
|
|
169551
|
+
if (!fs18.existsSync(systemMdPath)) {
|
|
169552
|
+
throw new Error(`missing system prompt file '${systemMdPath}'`);
|
|
169772
169553
|
}
|
|
169773
169554
|
}
|
|
169774
|
-
|
|
169775
|
-
|
|
169776
|
-
|
|
169777
|
-
|
|
169778
|
-
|
|
169779
|
-
|
|
169780
|
-
const length = comprehensiveHistory.length;
|
|
169781
|
-
let i4 = 0;
|
|
169782
|
-
while (i4 < length) {
|
|
169783
|
-
if (comprehensiveHistory[i4].role === "user") {
|
|
169784
|
-
curatedHistory.push(comprehensiveHistory[i4]);
|
|
169785
|
-
i4++;
|
|
169786
|
-
} else {
|
|
169787
|
-
const modelOutput = [];
|
|
169788
|
-
let isValid2 = true;
|
|
169789
|
-
while (i4 < length && comprehensiveHistory[i4].role === "model") {
|
|
169790
|
-
modelOutput.push(comprehensiveHistory[i4]);
|
|
169791
|
-
if (isValid2 && !isValidContent2(comprehensiveHistory[i4])) {
|
|
169792
|
-
isValid2 = false;
|
|
169793
|
-
}
|
|
169794
|
-
i4++;
|
|
169795
|
-
}
|
|
169796
|
-
if (isValid2) {
|
|
169797
|
-
curatedHistory.push(...modelOutput);
|
|
169798
|
-
}
|
|
169799
|
-
}
|
|
169800
|
-
}
|
|
169801
|
-
return curatedHistory;
|
|
169802
|
-
}
|
|
169803
|
-
function hasTruncationCascade(contents) {
|
|
169804
|
-
if (contents.length === 0)
|
|
169805
|
-
return false;
|
|
169806
|
-
const last2 = contents[contents.length - 1];
|
|
169807
|
-
if (last2.role !== "user")
|
|
169808
|
-
return false;
|
|
169809
|
-
return last2.parts?.some((p2) => {
|
|
169810
|
-
const err3 = p2.functionResponse?.response?.["error"];
|
|
169811
|
-
return typeof err3 === "string" && err3.includes(TRUNCATION_CASCADE_MARKER);
|
|
169812
|
-
}) ?? false;
|
|
169813
|
-
}
|
|
169814
|
-
function trimLargeToolResponsesFromContext(contents) {
|
|
169815
|
-
return contents.map((content) => {
|
|
169816
|
-
if (content.role !== "user" || !content.parts)
|
|
169817
|
-
return content;
|
|
169818
|
-
const needsTrim = content.parts.some((p2) => {
|
|
169819
|
-
const out2 = p2.functionResponse?.response?.["output"];
|
|
169820
|
-
return typeof out2 === "string" && out2.length > LARGE_TOOL_RESPONSE_TRIM_CHARS;
|
|
169821
|
-
});
|
|
169822
|
-
if (!needsTrim)
|
|
169823
|
-
return content;
|
|
169824
|
-
return {
|
|
169825
|
-
...content,
|
|
169826
|
-
parts: content.parts.map((p2) => {
|
|
169827
|
-
const out2 = p2.functionResponse?.response?.["output"];
|
|
169828
|
-
if (typeof out2 !== "string" || out2.length <= LARGE_TOOL_RESPONSE_TRIM_CHARS)
|
|
169829
|
-
return p2;
|
|
169830
|
-
const trimmed2 = out2.slice(0, LARGE_TOOL_RESPONSE_TRIM_CHARS) + `
|
|
169831
|
-
|
|
169832
|
-
[... output trimmed from ${out2.length} to ${LARGE_TOOL_RESPONSE_TRIM_CHARS} chars to reduce context size ...]`;
|
|
169833
|
-
return {
|
|
169834
|
-
...p2,
|
|
169835
|
-
functionResponse: {
|
|
169836
|
-
...p2.functionResponse,
|
|
169837
|
-
response: {
|
|
169838
|
-
...p2.functionResponse.response,
|
|
169839
|
-
output: trimmed2
|
|
169840
|
-
}
|
|
169841
|
-
}
|
|
169842
|
-
};
|
|
169843
|
-
})
|
|
169844
|
-
};
|
|
169845
|
-
});
|
|
169846
|
-
}
|
|
169847
|
-
function trimToolErrorsFromContext(contents, maxTrimPairs = 6) {
|
|
169848
|
-
const trimmed2 = [...contents];
|
|
169849
|
-
let trimmed_count = 0;
|
|
169850
|
-
while (trimmed2.length >= 2 && trimmed_count < maxTrimPairs) {
|
|
169851
|
-
const last2 = trimmed2[trimmed2.length - 1];
|
|
169852
|
-
const prev = trimmed2[trimmed2.length - 2];
|
|
169853
|
-
if (last2.role !== "user")
|
|
169854
|
-
break;
|
|
169855
|
-
const allErrors = last2.parts?.every((p2) => p2.functionResponse !== void 0 && typeof p2.functionResponse.response?.["error"] === "string");
|
|
169856
|
-
if (!allErrors)
|
|
169857
|
-
break;
|
|
169858
|
-
if (prev.role !== "model")
|
|
169859
|
-
break;
|
|
169860
|
-
const hasToolCall2 = prev.parts?.some((p2) => p2.functionCall !== void 0);
|
|
169861
|
-
if (!hasToolCall2)
|
|
169862
|
-
break;
|
|
169863
|
-
trimmed2.splice(trimmed2.length - 2, 2);
|
|
169864
|
-
trimmed_count++;
|
|
169865
|
-
}
|
|
169866
|
-
return trimmed2;
|
|
169867
|
-
}
|
|
169868
|
-
function isSchemaDepthError(errorMessage) {
|
|
169869
|
-
return errorMessage.includes("maximum schema depth exceeded");
|
|
169870
|
-
}
|
|
169871
|
-
function isInvalidArgumentError(errorMessage) {
|
|
169872
|
-
return errorMessage.includes("Request contains an invalid argument");
|
|
169873
|
-
}
|
|
169874
|
-
var debugLogger23, StreamEventType, INVALID_CONTENT_RETRY_OPTIONS, INVALID_STREAM_RETRY_CONFIG, RATE_LIMIT_RETRY_OPTIONS, TRUNCATION_CASCADE_MARKER, LARGE_TOOL_RESPONSE_TRIM_CHARS, InvalidStreamError, GeminiChat;
|
|
169875
|
-
var init_geminiChat = __esm({
|
|
169876
|
-
"packages/core/dist/src/core/geminiChat.js"() {
|
|
169877
|
-
"use strict";
|
|
169878
|
-
init_esbuild_shims();
|
|
169879
|
-
init_node();
|
|
169880
|
-
init_retry();
|
|
169881
|
-
init_errors();
|
|
169882
|
-
init_debugLogger();
|
|
169883
|
-
init_errorParsing();
|
|
169884
|
-
init_rateLimit();
|
|
169885
|
-
init_tools();
|
|
169886
|
-
init_loggers();
|
|
169887
|
-
init_chatRecordingService();
|
|
169888
|
-
init_types4();
|
|
169889
|
-
debugLogger23 = createDebugLogger("QWEN_CODE_CHAT");
|
|
169890
|
-
(function(StreamEventType2) {
|
|
169891
|
-
StreamEventType2["CHUNK"] = "chunk";
|
|
169892
|
-
StreamEventType2["RETRY"] = "retry";
|
|
169893
|
-
})(StreamEventType || (StreamEventType = {}));
|
|
169894
|
-
INVALID_CONTENT_RETRY_OPTIONS = {
|
|
169895
|
-
maxAttempts: 2,
|
|
169896
|
-
// 1 initial call + 1 retry
|
|
169897
|
-
initialDelayMs: 500
|
|
169898
|
-
};
|
|
169899
|
-
INVALID_STREAM_RETRY_CONFIG = {
|
|
169900
|
-
maxRetries: 2,
|
|
169901
|
-
initialDelayMs: 2e3
|
|
169902
|
-
};
|
|
169903
|
-
RATE_LIMIT_RETRY_OPTIONS = {
|
|
169904
|
-
maxRetries: 10,
|
|
169905
|
-
delayMs: 6e4
|
|
169906
|
-
};
|
|
169907
|
-
__name(isValidResponse2, "isValidResponse");
|
|
169908
|
-
__name(isValidNonThoughtTextPart, "isValidNonThoughtTextPart");
|
|
169909
|
-
__name(isValidContent2, "isValidContent");
|
|
169910
|
-
__name(isValidContentPart, "isValidContentPart");
|
|
169911
|
-
__name(validateHistory2, "validateHistory");
|
|
169912
|
-
__name(extractCuratedHistory2, "extractCuratedHistory");
|
|
169913
|
-
TRUNCATION_CASCADE_MARKER = "truncated due to max_tokens limit";
|
|
169914
|
-
LARGE_TOOL_RESPONSE_TRIM_CHARS = 1e4;
|
|
169915
|
-
__name(hasTruncationCascade, "hasTruncationCascade");
|
|
169916
|
-
__name(trimLargeToolResponsesFromContext, "trimLargeToolResponsesFromContext");
|
|
169917
|
-
__name(trimToolErrorsFromContext, "trimToolErrorsFromContext");
|
|
169918
|
-
InvalidStreamError = class extends Error {
|
|
169919
|
-
static {
|
|
169920
|
-
__name(this, "InvalidStreamError");
|
|
169921
|
-
}
|
|
169922
|
-
type;
|
|
169923
|
-
constructor(message, type) {
|
|
169924
|
-
super(message);
|
|
169925
|
-
this.name = "InvalidStreamError";
|
|
169926
|
-
this.type = type;
|
|
169927
|
-
}
|
|
169928
|
-
};
|
|
169929
|
-
GeminiChat = class {
|
|
169930
|
-
static {
|
|
169931
|
-
__name(this, "GeminiChat");
|
|
169932
|
-
}
|
|
169933
|
-
config;
|
|
169934
|
-
generationConfig;
|
|
169935
|
-
history;
|
|
169936
|
-
chatRecordingService;
|
|
169937
|
-
telemetryService;
|
|
169938
|
-
// A promise to represent the current state of the message being sent to the
|
|
169939
|
-
// model.
|
|
169940
|
-
sendPromise = Promise.resolve();
|
|
169941
|
-
/**
|
|
169942
|
-
* Creates a new GeminiChat instance.
|
|
169943
|
-
*
|
|
169944
|
-
* @param config - The configuration object.
|
|
169945
|
-
* @param generationConfig - Optional generation configuration.
|
|
169946
|
-
* @param history - Optional initial conversation history.
|
|
169947
|
-
* @param chatRecordingService - Optional recording service. If provided, chat
|
|
169948
|
-
* messages will be recorded.
|
|
169949
|
-
* @param telemetryService - Optional UI telemetry service. When provided,
|
|
169950
|
-
* prompt token counts are reported on each API response. Pass `undefined`
|
|
169951
|
-
* for sub-agent chats to avoid overwriting the main agent's context usage.
|
|
169952
|
-
*/
|
|
169953
|
-
constructor(config2, generationConfig = {}, history = [], chatRecordingService, telemetryService) {
|
|
169954
|
-
this.config = config2;
|
|
169955
|
-
this.generationConfig = generationConfig;
|
|
169956
|
-
this.history = history;
|
|
169957
|
-
this.chatRecordingService = chatRecordingService;
|
|
169958
|
-
this.telemetryService = telemetryService;
|
|
169959
|
-
validateHistory2(history);
|
|
169960
|
-
}
|
|
169961
|
-
setSystemInstruction(sysInstr) {
|
|
169962
|
-
this.generationConfig.systemInstruction = sysInstr;
|
|
169963
|
-
}
|
|
169964
|
-
/**
|
|
169965
|
-
* Sends a message to the model and returns the response in chunks.
|
|
169966
|
-
*
|
|
169967
|
-
* @remarks
|
|
169968
|
-
* This method will wait for the previous message to be processed before
|
|
169969
|
-
* sending the next message.
|
|
169970
|
-
*
|
|
169971
|
-
* @see {@link Chat#sendMessage} for non-streaming method.
|
|
169972
|
-
* @param params - parameters for sending the message.
|
|
169973
|
-
* @return The model's response.
|
|
169974
|
-
*
|
|
169975
|
-
* @example
|
|
169976
|
-
* ```ts
|
|
169977
|
-
* const chat = ai.chats.create({model: 'gemini-2.0-flash'});
|
|
169978
|
-
* const response = await chat.sendMessageStream({
|
|
169979
|
-
* message: 'Why is the sky blue?'
|
|
169980
|
-
* });
|
|
169981
|
-
* for await (const chunk of response) {
|
|
169982
|
-
* console.log(chunk.text);
|
|
169983
|
-
* }
|
|
169984
|
-
* ```
|
|
169985
|
-
*/
|
|
169986
|
-
async sendMessageStream(model, params, prompt_id) {
|
|
169987
|
-
await this.sendPromise;
|
|
169988
|
-
let streamDoneResolver;
|
|
169989
|
-
const streamDonePromise = new Promise((resolve37) => {
|
|
169990
|
-
streamDoneResolver = resolve37;
|
|
169991
|
-
});
|
|
169992
|
-
this.sendPromise = streamDonePromise;
|
|
169993
|
-
const userContent = createUserContent(params.message);
|
|
169994
|
-
this.history.push(userContent);
|
|
169995
|
-
let requestContents = this.getHistory(true);
|
|
169996
|
-
if (hasTruncationCascade(requestContents)) {
|
|
169997
|
-
const withoutErrors = trimToolErrorsFromContext(requestContents);
|
|
169998
|
-
requestContents = trimLargeToolResponsesFromContext(withoutErrors);
|
|
169999
|
-
debugLogger23.warn(`MAX_TOKENS cascade detected: trimmed context from ${this.getHistory(true).length} to ${requestContents.length} entries and capped large tool responses.`);
|
|
170000
|
-
}
|
|
170001
|
-
const self2 = this;
|
|
170002
|
-
return async function* () {
|
|
170003
|
-
try {
|
|
170004
|
-
let lastError = new Error("Request failed after all retries.");
|
|
170005
|
-
let rateLimitRetryCount = 0;
|
|
170006
|
-
let invalidStreamRetryCount = 0;
|
|
170007
|
-
const cgConfig = self2.config.getContentGeneratorConfig();
|
|
170008
|
-
const maxRateLimitRetries = cgConfig?.maxRetries ?? RATE_LIMIT_RETRY_OPTIONS.maxRetries;
|
|
170009
|
-
const extraRetryErrorCodes = cgConfig?.retryErrorCodes;
|
|
170010
|
-
for (let attempt = 0; attempt < INVALID_CONTENT_RETRY_OPTIONS.maxAttempts; attempt++) {
|
|
170011
|
-
try {
|
|
170012
|
-
if (attempt > 0 || rateLimitRetryCount > 0 || invalidStreamRetryCount > 0) {
|
|
170013
|
-
yield { type: StreamEventType.RETRY };
|
|
170014
|
-
}
|
|
170015
|
-
const stream2 = await self2.makeApiCallAndProcessStream(model, requestContents, params, prompt_id);
|
|
170016
|
-
for await (const chunk of stream2) {
|
|
170017
|
-
yield { type: StreamEventType.CHUNK, value: chunk };
|
|
170018
|
-
}
|
|
170019
|
-
lastError = null;
|
|
170020
|
-
break;
|
|
170021
|
-
} catch (error40) {
|
|
170022
|
-
lastError = error40;
|
|
170023
|
-
const isRateLimit = isRateLimitError(error40, extraRetryErrorCodes);
|
|
170024
|
-
if (isRateLimit && rateLimitRetryCount < maxRateLimitRetries) {
|
|
170025
|
-
rateLimitRetryCount++;
|
|
170026
|
-
const delayMs = RATE_LIMIT_RETRY_OPTIONS.delayMs;
|
|
170027
|
-
const message = parseAndFormatApiError(error40 instanceof Error ? error40.message : String(error40));
|
|
170028
|
-
debugLogger23.warn(`Rate limit throttling detected (retry ${rateLimitRetryCount}/${maxRateLimitRetries}). Waiting ${delayMs / 1e3}s before retrying...`);
|
|
170029
|
-
yield {
|
|
170030
|
-
type: StreamEventType.RETRY,
|
|
170031
|
-
retryInfo: {
|
|
170032
|
-
message,
|
|
170033
|
-
attempt: rateLimitRetryCount,
|
|
170034
|
-
maxRetries: maxRateLimitRetries,
|
|
170035
|
-
delayMs
|
|
170036
|
-
}
|
|
170037
|
-
};
|
|
170038
|
-
attempt--;
|
|
170039
|
-
await new Promise((res) => setTimeout(res, delayMs));
|
|
170040
|
-
continue;
|
|
170041
|
-
}
|
|
170042
|
-
const isTransientStreamError = error40 instanceof InvalidStreamError;
|
|
170043
|
-
if (isTransientStreamError && invalidStreamRetryCount < INVALID_STREAM_RETRY_CONFIG.maxRetries) {
|
|
170044
|
-
invalidStreamRetryCount++;
|
|
170045
|
-
const delayMs = INVALID_STREAM_RETRY_CONFIG.initialDelayMs * invalidStreamRetryCount;
|
|
170046
|
-
debugLogger23.warn(`Invalid stream [${error40.type}] (retry ${invalidStreamRetryCount}/${INVALID_STREAM_RETRY_CONFIG.maxRetries}). Waiting ${delayMs / 1e3}s before retrying...`);
|
|
170047
|
-
logContentRetry(self2.config, new ContentRetryEvent(invalidStreamRetryCount - 1, error40.type, delayMs, model));
|
|
170048
|
-
yield { type: StreamEventType.RETRY };
|
|
170049
|
-
attempt--;
|
|
170050
|
-
await new Promise((res) => setTimeout(res, delayMs));
|
|
170051
|
-
continue;
|
|
170052
|
-
}
|
|
170053
|
-
if (isTransientStreamError && error40.type === "NO_RESPONSE_TEXT") {
|
|
170054
|
-
const trimmedContents = trimToolErrorsFromContext(requestContents);
|
|
170055
|
-
if (trimmedContents.length < requestContents.length) {
|
|
170056
|
-
debugLogger23.warn(`NO_RESPONSE_TEXT: retrying with trimmed context (removed ${requestContents.length - trimmedContents.length} tool-error messages)`);
|
|
170057
|
-
try {
|
|
170058
|
-
const stream2 = await self2.makeApiCallAndProcessStream(model, trimmedContents, params, prompt_id);
|
|
170059
|
-
for await (const chunk of stream2) {
|
|
170060
|
-
yield { type: StreamEventType.CHUNK, value: chunk };
|
|
170061
|
-
}
|
|
170062
|
-
lastError = null;
|
|
170063
|
-
} catch {
|
|
170064
|
-
}
|
|
170065
|
-
}
|
|
170066
|
-
break;
|
|
170067
|
-
}
|
|
170068
|
-
if (isTransientStreamError) {
|
|
170069
|
-
break;
|
|
170070
|
-
}
|
|
170071
|
-
const isContentError = error40 instanceof InvalidStreamError;
|
|
170072
|
-
if (isContentError) {
|
|
170073
|
-
if (attempt < INVALID_CONTENT_RETRY_OPTIONS.maxAttempts - 1) {
|
|
170074
|
-
logContentRetry(self2.config, new ContentRetryEvent(attempt, error40.type, INVALID_CONTENT_RETRY_OPTIONS.initialDelayMs, model));
|
|
170075
|
-
await new Promise((res) => setTimeout(res, INVALID_CONTENT_RETRY_OPTIONS.initialDelayMs * (attempt + 1)));
|
|
170076
|
-
continue;
|
|
170077
|
-
}
|
|
170078
|
-
}
|
|
170079
|
-
break;
|
|
170080
|
-
}
|
|
170081
|
-
}
|
|
170082
|
-
if (lastError) {
|
|
170083
|
-
if (lastError instanceof InvalidStreamError) {
|
|
170084
|
-
const totalAttempts = invalidStreamRetryCount + 1;
|
|
170085
|
-
logContentRetryFailure(self2.config, new ContentRetryFailureEvent(totalAttempts, lastError.type, model));
|
|
170086
|
-
}
|
|
170087
|
-
throw lastError;
|
|
170088
|
-
}
|
|
170089
|
-
} finally {
|
|
170090
|
-
streamDoneResolver();
|
|
170091
|
-
}
|
|
170092
|
-
}();
|
|
170093
|
-
}
|
|
170094
|
-
async makeApiCallAndProcessStream(model, requestContents, params, prompt_id) {
|
|
170095
|
-
const apiCall = /* @__PURE__ */ __name(() => this.config.getContentGenerator().generateContentStream({
|
|
170096
|
-
model,
|
|
170097
|
-
contents: requestContents,
|
|
170098
|
-
config: { ...this.generationConfig, ...params.config }
|
|
170099
|
-
}, prompt_id), "apiCall");
|
|
170100
|
-
const streamResponse2 = await retryWithBackoff(apiCall, {
|
|
170101
|
-
shouldRetryOnError: /* @__PURE__ */ __name((error40) => {
|
|
170102
|
-
if (error40 instanceof Error) {
|
|
170103
|
-
if (isSchemaDepthError(error40.message))
|
|
170104
|
-
return false;
|
|
170105
|
-
if (isInvalidArgumentError(error40.message))
|
|
170106
|
-
return false;
|
|
170107
|
-
}
|
|
170108
|
-
const status = getErrorStatus(error40);
|
|
170109
|
-
if (status === 400)
|
|
170110
|
-
return false;
|
|
170111
|
-
if (status === 429)
|
|
170112
|
-
return true;
|
|
170113
|
-
if (status && status >= 500 && status < 600)
|
|
170114
|
-
return true;
|
|
170115
|
-
return false;
|
|
170116
|
-
}, "shouldRetryOnError")
|
|
170117
|
-
});
|
|
170118
|
-
return this.processStreamResponse(model, streamResponse2);
|
|
170119
|
-
}
|
|
170120
|
-
/**
|
|
170121
|
-
* Returns the chat history.
|
|
170122
|
-
*
|
|
170123
|
-
* @remarks
|
|
170124
|
-
* The history is a list of contents alternating between user and model.
|
|
170125
|
-
*
|
|
170126
|
-
* There are two types of history:
|
|
170127
|
-
* - The `curated history` contains only the valid turns between user and
|
|
170128
|
-
* model, which will be included in the subsequent requests sent to the model.
|
|
170129
|
-
* - The `comprehensive history` contains all turns, including invalid or
|
|
170130
|
-
* empty model outputs, providing a complete record of the history.
|
|
170131
|
-
*
|
|
170132
|
-
* The history is updated after receiving the response from the model,
|
|
170133
|
-
* for streaming response, it means receiving the last chunk of the response.
|
|
170134
|
-
*
|
|
170135
|
-
* The `comprehensive history` is returned by default. To get the `curated
|
|
170136
|
-
* history`, set the `curated` parameter to `true`.
|
|
170137
|
-
*
|
|
170138
|
-
* @param curated - whether to return the curated history or the comprehensive
|
|
170139
|
-
* history.
|
|
170140
|
-
* @return History contents alternating between user and model for the entire
|
|
170141
|
-
* chat session.
|
|
170142
|
-
*/
|
|
170143
|
-
getHistory(curated = false) {
|
|
170144
|
-
const history = curated ? extractCuratedHistory2(this.history) : this.history;
|
|
170145
|
-
return structuredClone(history);
|
|
170146
|
-
}
|
|
170147
|
-
/**
|
|
170148
|
-
* Clears the chat history.
|
|
170149
|
-
*/
|
|
170150
|
-
clearHistory() {
|
|
170151
|
-
this.history = [];
|
|
170152
|
-
}
|
|
170153
|
-
/**
|
|
170154
|
-
* Adds a new entry to the chat history.
|
|
170155
|
-
*/
|
|
170156
|
-
addHistory(content) {
|
|
170157
|
-
this.history.push(content);
|
|
170158
|
-
}
|
|
170159
|
-
setHistory(history) {
|
|
170160
|
-
this.history = history;
|
|
170161
|
-
}
|
|
170162
|
-
stripThoughtsFromHistory() {
|
|
170163
|
-
this.history = this.history.map((content) => {
|
|
170164
|
-
if (!content.parts)
|
|
170165
|
-
return content;
|
|
170166
|
-
const filteredParts = content.parts.filter((part) => !(part && typeof part === "object" && "thought" in part && part.thought)).map((part) => {
|
|
170167
|
-
if (part && typeof part === "object" && "thoughtSignature" in part) {
|
|
170168
|
-
const newPart = { ...part };
|
|
170169
|
-
delete newPart.thoughtSignature;
|
|
170170
|
-
return newPart;
|
|
170171
|
-
}
|
|
170172
|
-
return part;
|
|
170173
|
-
});
|
|
170174
|
-
return {
|
|
170175
|
-
...content,
|
|
170176
|
-
parts: filteredParts
|
|
170177
|
-
};
|
|
170178
|
-
}).filter((content) => content.parts && content.parts.length > 0);
|
|
170179
|
-
}
|
|
170180
|
-
/**
|
|
170181
|
-
* Pop all orphaned trailing user entries from chat history.
|
|
170182
|
-
* In a valid conversation the last entry is always a model response;
|
|
170183
|
-
* any trailing user entries are leftovers from a request that failed.
|
|
170184
|
-
*/
|
|
170185
|
-
stripOrphanedUserEntriesFromHistory() {
|
|
170186
|
-
while (this.history.length > 0 && this.history[this.history.length - 1].role === "user") {
|
|
170187
|
-
this.history.pop();
|
|
170188
|
-
}
|
|
170189
|
-
}
|
|
170190
|
-
setTools(tools) {
|
|
170191
|
-
this.generationConfig.tools = tools;
|
|
170192
|
-
}
|
|
170193
|
-
/** Returns a shallow copy of the current generation config (for cache param snapshots). */
|
|
170194
|
-
getGenerationConfig() {
|
|
170195
|
-
return { ...this.generationConfig };
|
|
170196
|
-
}
|
|
170197
|
-
async maybeIncludeSchemaDepthContext(error40) {
|
|
170198
|
-
if (isSchemaDepthError(error40.message) || isInvalidArgumentError(error40.message)) {
|
|
170199
|
-
const tools = this.config.getToolRegistry().getAllTools();
|
|
170200
|
-
const cyclicSchemaTools = [];
|
|
170201
|
-
for (const tool of tools) {
|
|
170202
|
-
if (tool.schema.parametersJsonSchema && hasCycleInSchema(tool.schema.parametersJsonSchema) || tool.schema.parameters && hasCycleInSchema(tool.schema.parameters)) {
|
|
170203
|
-
cyclicSchemaTools.push(tool.displayName);
|
|
170204
|
-
}
|
|
170205
|
-
}
|
|
170206
|
-
if (cyclicSchemaTools.length > 0) {
|
|
170207
|
-
const extraDetails = `
|
|
170208
|
-
|
|
170209
|
-
This error was probably caused by cyclic schema references in one of the following tools, try disabling them with excludeTools:
|
|
170210
|
-
|
|
170211
|
-
- ` + cyclicSchemaTools.join(`
|
|
170212
|
-
- `) + `
|
|
170213
|
-
`;
|
|
170214
|
-
error40.message += extraDetails;
|
|
170215
|
-
}
|
|
170216
|
-
}
|
|
170217
|
-
}
|
|
170218
|
-
async *processStreamResponse(model, streamResponse2) {
|
|
170219
|
-
const allModelParts = [];
|
|
170220
|
-
let usageMetadata;
|
|
170221
|
-
let hasToolCall2 = false;
|
|
170222
|
-
let hasFinishReason = false;
|
|
170223
|
-
for await (const chunk of streamResponse2) {
|
|
170224
|
-
hasFinishReason ||= chunk?.candidates?.some((candidate) => candidate.finishReason) ?? false;
|
|
170225
|
-
if (isValidResponse2(chunk)) {
|
|
170226
|
-
const content = chunk.candidates?.[0]?.content;
|
|
170227
|
-
if (content?.parts) {
|
|
170228
|
-
if (content.parts.some((part) => part.functionCall)) {
|
|
170229
|
-
hasToolCall2 = true;
|
|
170230
|
-
}
|
|
170231
|
-
allModelParts.push(...content.parts);
|
|
170232
|
-
}
|
|
170233
|
-
}
|
|
170234
|
-
if (chunk.usageMetadata) {
|
|
170235
|
-
usageMetadata = chunk.usageMetadata;
|
|
170236
|
-
const lastPromptTokenCount = usageMetadata.totalTokenCount || usageMetadata.promptTokenCount;
|
|
170237
|
-
if (lastPromptTokenCount && this.telemetryService) {
|
|
170238
|
-
this.telemetryService.setLastPromptTokenCount(lastPromptTokenCount);
|
|
170239
|
-
}
|
|
170240
|
-
if (usageMetadata.cachedContentTokenCount && this.telemetryService) {
|
|
170241
|
-
this.telemetryService.setLastCachedContentTokenCount(usageMetadata.cachedContentTokenCount);
|
|
170242
|
-
}
|
|
170243
|
-
}
|
|
170244
|
-
yield chunk;
|
|
170245
|
-
}
|
|
170246
|
-
let thoughtContentPart;
|
|
170247
|
-
const thoughtText = allModelParts.filter((part) => part.thought).map((part) => part.text).join("").trim();
|
|
170248
|
-
if (thoughtText !== "") {
|
|
170249
|
-
thoughtContentPart = {
|
|
170250
|
-
text: thoughtText,
|
|
170251
|
-
thought: true
|
|
170252
|
-
};
|
|
170253
|
-
const thoughtSignature = allModelParts.filter((part) => part.thoughtSignature && part.thought)?.[0]?.thoughtSignature;
|
|
170254
|
-
if (thoughtContentPart && thoughtSignature) {
|
|
170255
|
-
thoughtContentPart.thoughtSignature = thoughtSignature;
|
|
170256
|
-
}
|
|
170257
|
-
}
|
|
170258
|
-
const contentParts = allModelParts.filter((part) => !part.thought);
|
|
170259
|
-
const consolidatedHistoryParts = [];
|
|
170260
|
-
for (const part of contentParts) {
|
|
170261
|
-
const lastPart = consolidatedHistoryParts[consolidatedHistoryParts.length - 1];
|
|
170262
|
-
if (lastPart?.text && isValidNonThoughtTextPart(lastPart) && isValidNonThoughtTextPart(part)) {
|
|
170263
|
-
lastPart.text += part.text;
|
|
170264
|
-
} else if (isValidContentPart(part)) {
|
|
170265
|
-
consolidatedHistoryParts.push(part);
|
|
170266
|
-
}
|
|
170267
|
-
}
|
|
170268
|
-
const contentText = consolidatedHistoryParts.filter((part) => part.text).map((part) => part.text).join("").trim();
|
|
170269
|
-
if (thoughtContentPart || contentText || hasToolCall2 || usageMetadata) {
|
|
170270
|
-
const contextWindowSize = this.config.getContentGeneratorConfig()?.contextWindowSize;
|
|
170271
|
-
this.chatRecordingService?.recordAssistantTurn({
|
|
170272
|
-
model,
|
|
170273
|
-
message: [
|
|
170274
|
-
...thoughtContentPart ? [thoughtContentPart] : [],
|
|
170275
|
-
...contentText ? [{ text: contentText }] : [],
|
|
170276
|
-
...hasToolCall2 ? contentParts.filter((part) => part.functionCall).map((part) => ({ functionCall: part.functionCall })) : []
|
|
170277
|
-
],
|
|
170278
|
-
tokens: usageMetadata,
|
|
170279
|
-
contextWindowSize
|
|
170280
|
-
});
|
|
170281
|
-
}
|
|
170282
|
-
if (!hasToolCall2 && (!hasFinishReason || !contentText)) {
|
|
170283
|
-
if (!hasFinishReason) {
|
|
170284
|
-
throw new InvalidStreamError("Model stream ended without a finish reason.", "NO_FINISH_REASON");
|
|
170285
|
-
} else {
|
|
170286
|
-
throw new InvalidStreamError("Model stream ended with empty response text.", "NO_RESPONSE_TEXT");
|
|
170287
|
-
}
|
|
170288
|
-
}
|
|
170289
|
-
this.history.push({
|
|
170290
|
-
role: "model",
|
|
170291
|
-
parts: [
|
|
170292
|
-
...thoughtContentPart ? [thoughtContentPart] : [],
|
|
170293
|
-
...consolidatedHistoryParts
|
|
170294
|
-
]
|
|
170295
|
-
});
|
|
170296
|
-
}
|
|
170297
|
-
};
|
|
170298
|
-
__name(isSchemaDepthError, "isSchemaDepthError");
|
|
170299
|
-
__name(isInvalidArgumentError, "isInvalidArgumentError");
|
|
170300
|
-
}
|
|
170301
|
-
});
|
|
170302
|
-
|
|
170303
|
-
// packages/core/dist/src/core/prompts.js
|
|
170304
|
-
import path19 from "node:path";
|
|
170305
|
-
import fs20 from "node:fs";
|
|
170306
|
-
import os6 from "node:os";
|
|
170307
|
-
import { execSync as execSync3 } from "node:child_process";
|
|
170308
|
-
import process3 from "node:process";
|
|
170309
|
-
function assemblePromptSections(sections) {
|
|
170310
|
-
const stable = sections.filter((s5) => s5.volatility === "stable" && s5.content);
|
|
170311
|
-
const workspace = sections.filter((s5) => s5.volatility === "workspace" && s5.content);
|
|
170312
|
-
const run3 = sections.filter((s5) => s5.volatility === "run" && s5.content);
|
|
170313
|
-
const stablePart = stable.map((s5) => s5.content).join("\n\n");
|
|
170314
|
-
const nonStable = [...workspace, ...run3].map((s5) => s5.content).join("\n\n");
|
|
170315
|
-
if (!stablePart)
|
|
170316
|
-
return nonStable;
|
|
170317
|
-
if (!nonStable)
|
|
170318
|
-
return stablePart;
|
|
170319
|
-
return `${stablePart}${CACHE_BOUNDARY_SENTINEL}${nonStable}`;
|
|
170320
|
-
}
|
|
170321
|
-
function resolvePathFromEnv(envVar) {
|
|
170322
|
-
const trimmedEnvVar = envVar?.trim();
|
|
170323
|
-
if (!trimmedEnvVar) {
|
|
170324
|
-
return { isSwitch: false, value: null, isDisabled: false };
|
|
170325
|
-
}
|
|
170326
|
-
const lowerEnvVar = trimmedEnvVar.toLowerCase();
|
|
170327
|
-
if (["0", "false", "1", "true"].includes(lowerEnvVar)) {
|
|
170328
|
-
const isDisabled = ["0", "false"].includes(lowerEnvVar);
|
|
170329
|
-
return { isSwitch: true, value: lowerEnvVar, isDisabled };
|
|
170330
|
-
}
|
|
170331
|
-
let customPath = trimmedEnvVar;
|
|
170332
|
-
if (customPath.startsWith("~/") || customPath === "~") {
|
|
170333
|
-
try {
|
|
170334
|
-
const home = os6.homedir();
|
|
170335
|
-
if (customPath === "~") {
|
|
170336
|
-
customPath = home;
|
|
170337
|
-
} else {
|
|
170338
|
-
customPath = path19.join(home, customPath.slice(2));
|
|
170339
|
-
}
|
|
170340
|
-
} catch (error40) {
|
|
170341
|
-
debugLogger24.warn(`Could not resolve home directory for path: ${trimmedEnvVar}`, error40);
|
|
170342
|
-
return { isSwitch: false, value: null, isDisabled: false };
|
|
170343
|
-
}
|
|
170344
|
-
}
|
|
170345
|
-
return {
|
|
170346
|
-
isSwitch: false,
|
|
170347
|
-
value: path19.resolve(customPath),
|
|
170348
|
-
isDisabled: false
|
|
170349
|
-
};
|
|
170350
|
-
}
|
|
170351
|
-
function getCustomSystemPrompt(customInstruction, userMemory, appendInstruction) {
|
|
170352
|
-
let instructionText = "";
|
|
170353
|
-
if (typeof customInstruction === "string") {
|
|
170354
|
-
instructionText = customInstruction;
|
|
170355
|
-
} else if (Array.isArray(customInstruction)) {
|
|
170356
|
-
instructionText = customInstruction.map((part) => typeof part === "string" ? part : part.text || "").join("");
|
|
170357
|
-
} else if (customInstruction && "parts" in customInstruction) {
|
|
170358
|
-
instructionText = customInstruction.parts?.map((part) => typeof part === "string" ? part : part.text || "").join("") || "";
|
|
170359
|
-
} else if (customInstruction && "text" in customInstruction) {
|
|
170360
|
-
instructionText = customInstruction.text || "";
|
|
170361
|
-
}
|
|
170362
|
-
const memorySuffix = buildSystemPromptSuffix(userMemory);
|
|
170363
|
-
return `${instructionText}${memorySuffix}${buildSystemPromptSuffix(appendInstruction)}`;
|
|
170364
|
-
}
|
|
170365
|
-
function buildSystemPromptSuffix(text) {
|
|
170366
|
-
const trimmed2 = text?.trim();
|
|
170367
|
-
return trimmed2 ? `
|
|
170368
|
-
|
|
170369
|
-
---
|
|
170370
|
-
|
|
170371
|
-
${trimmed2}` : "";
|
|
170372
|
-
}
|
|
170373
|
-
function getCoreSystemPrompt(userMemory, model, appendInstruction, interactive = false) {
|
|
170374
|
-
let systemMdEnabled = false;
|
|
170375
|
-
let systemMdPath = path19.resolve(path19.join(QWEN_CONFIG_DIR, "system.md"));
|
|
170376
|
-
const systemMdResolution = resolvePathFromEnv(process3.env["QWEN_SYSTEM_MD"]);
|
|
170377
|
-
if (systemMdResolution.value && !systemMdResolution.isDisabled) {
|
|
170378
|
-
systemMdEnabled = true;
|
|
170379
|
-
if (!systemMdResolution.isSwitch) {
|
|
170380
|
-
systemMdPath = systemMdResolution.value;
|
|
170381
|
-
}
|
|
170382
|
-
if (!fs20.existsSync(systemMdPath)) {
|
|
170383
|
-
throw new Error(`missing system prompt file '${systemMdPath}'`);
|
|
170384
|
-
}
|
|
170385
|
-
}
|
|
170386
|
-
if (systemMdEnabled) {
|
|
170387
|
-
const customPrompt = fs20.readFileSync(systemMdPath, "utf8");
|
|
170388
|
-
const memorySuffix2 = buildSystemPromptSuffix(userMemory);
|
|
170389
|
-
const appendSuffix2 = buildSystemPromptSuffix(appendInstruction);
|
|
170390
|
-
const full2 = `${customPrompt}${memorySuffix2}${appendSuffix2}`;
|
|
170391
|
-
return { staticPrefix: full2, dynamicSuffix: "", full: full2 };
|
|
169555
|
+
if (systemMdEnabled) {
|
|
169556
|
+
const customPrompt = fs18.readFileSync(systemMdPath, "utf8");
|
|
169557
|
+
const memorySuffix2 = buildSystemPromptSuffix(userMemory);
|
|
169558
|
+
const appendSuffix2 = buildSystemPromptSuffix(appendInstruction);
|
|
169559
|
+
const full2 = `${customPrompt}${memorySuffix2}${appendSuffix2}`;
|
|
169560
|
+
return { staticPrefix: full2, dynamicSuffix: "", full: full2 };
|
|
170392
169561
|
}
|
|
170393
169562
|
const staticPrefix = `
|
|
170394
169563
|
You are proto, an interactive CLI agent built by protoLabs.studio, specializing in software engineering tasks. Your primary goal is to help users safely and efficiently, adhering strictly to the following instructions and utilizing your available tools.
|
|
@@ -170637,7 +169806,7 @@ Workspace: ${parts2} files
|
|
|
170637
169806
|
${function() {
|
|
170638
169807
|
if (!interactive)
|
|
170639
169808
|
return "";
|
|
170640
|
-
if (!
|
|
169809
|
+
if (!fs18.existsSync(path17.join(process3.cwd(), ".beads")))
|
|
170641
169810
|
return "";
|
|
170642
169811
|
return `
|
|
170643
169812
|
# Beads (cross-session task tracker)
|
|
@@ -170673,8 +169842,8 @@ Your core function is efficient and safe assistance. Balance extreme conciseness
|
|
|
170673
169842
|
const writeSystemMdResolution = resolvePathFromEnv(process3.env["QWEN_WRITE_SYSTEM_MD"]);
|
|
170674
169843
|
if (writeSystemMdResolution.value && !writeSystemMdResolution.isDisabled) {
|
|
170675
169844
|
const writePath = writeSystemMdResolution.isSwitch ? systemMdPath : writeSystemMdResolution.value;
|
|
170676
|
-
|
|
170677
|
-
|
|
169845
|
+
fs18.mkdirSync(path17.dirname(writePath), { recursive: true });
|
|
169846
|
+
fs18.writeFileSync(writePath, basePrompt);
|
|
170678
169847
|
}
|
|
170679
169848
|
const memorySuffix = userMemory && userMemory.trim().length > 0 ? buildSystemPromptSuffix(userMemory) : "";
|
|
170680
169849
|
const appendSuffix = buildSystemPromptSuffix(appendInstruction);
|
|
@@ -170781,7 +169950,7 @@ function getToolCallExamples(model) {
|
|
|
170781
169950
|
case "general":
|
|
170782
169951
|
return generalToolCallExamples;
|
|
170783
169952
|
default:
|
|
170784
|
-
|
|
169953
|
+
debugLogger21.warn(`Unknown QWEN_CODE_TOOL_CALL_STYLE value: ${toolCallStyle}. Using model-based detection.`);
|
|
170785
169954
|
break;
|
|
170786
169955
|
}
|
|
170787
169956
|
}
|
|
@@ -170834,7 +170003,7 @@ function buildCapabilityManifest(mcpToolsByServer, activeSkills) {
|
|
|
170834
170003
|
|
|
170835
170004
|
${sections.join("\n\n")}`;
|
|
170836
170005
|
}
|
|
170837
|
-
var
|
|
170006
|
+
var debugLogger21, CACHE_BOUNDARY_SENTINEL, generalToolCallExamples, qwenCoderToolCallExamples, qwenVlToolCallExamples, INSIGHT_PROMPTS;
|
|
170838
170007
|
var init_prompts = __esm({
|
|
170839
170008
|
"packages/core/dist/src/core/prompts.js"() {
|
|
170840
170009
|
"use strict";
|
|
@@ -170843,7 +170012,7 @@ var init_prompts = __esm({
|
|
|
170843
170012
|
init_gitUtils();
|
|
170844
170013
|
init_memoryTool();
|
|
170845
170014
|
init_debugLogger();
|
|
170846
|
-
|
|
170015
|
+
debugLogger21 = createDebugLogger("PROMPTS");
|
|
170847
170016
|
CACHE_BOUNDARY_SENTINEL = "\n__CACHE_BOUNDARY__\n";
|
|
170848
170017
|
__name(assemblePromptSections, "assemblePromptSections");
|
|
170849
170018
|
__name(resolvePathFromEnv, "resolvePathFromEnv");
|
|
@@ -171362,320 +170531,6 @@ Call respond_in_schema function with A VALID JSON OBJECT as argument:
|
|
|
171362
170531
|
}
|
|
171363
170532
|
});
|
|
171364
170533
|
|
|
171365
|
-
// packages/core/dist/src/backgroundShells/notifications.js
|
|
171366
|
-
function escapeXml(text) {
|
|
171367
|
-
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
171368
|
-
}
|
|
171369
|
-
function buildBackgroundTaskNotification(task) {
|
|
171370
|
-
const exitLine = task.exitCode !== void 0 && task.exitCode !== null ? `
|
|
171371
|
-
<exit_code>${task.exitCode}</exit_code>` : "";
|
|
171372
|
-
const summary = (() => {
|
|
171373
|
-
const desc2 = task.description || task.command;
|
|
171374
|
-
switch (task.status) {
|
|
171375
|
-
case "completed":
|
|
171376
|
-
return `Background command "${desc2}" completed${task.exitCode != null ? ` (exit code ${task.exitCode})` : ""}.`;
|
|
171377
|
-
case "failed":
|
|
171378
|
-
return `Background command "${desc2}" failed${task.exitCode != null ? ` with exit code ${task.exitCode}` : ""}.`;
|
|
171379
|
-
case "killed":
|
|
171380
|
-
return `Background command "${desc2}" was stopped.`;
|
|
171381
|
-
default:
|
|
171382
|
-
return `Background command "${desc2}" ended in unknown state.`;
|
|
171383
|
-
}
|
|
171384
|
-
})();
|
|
171385
|
-
return [
|
|
171386
|
-
"<task_notification>",
|
|
171387
|
-
`<task_id>${task.id}</task_id>`,
|
|
171388
|
-
`<output_file>${task.outputPath}</output_file>`,
|
|
171389
|
-
`<status>${task.status}</status>${exitLine}`,
|
|
171390
|
-
`<summary>${escapeXml(summary)}</summary>`,
|
|
171391
|
-
"</task_notification>",
|
|
171392
|
-
"",
|
|
171393
|
-
`Read ${task.outputPath} to see the full output.`
|
|
171394
|
-
].join("\n");
|
|
171395
|
-
}
|
|
171396
|
-
var init_notifications = __esm({
|
|
171397
|
-
"packages/core/dist/src/backgroundShells/notifications.js"() {
|
|
171398
|
-
"use strict";
|
|
171399
|
-
init_esbuild_shims();
|
|
171400
|
-
__name(escapeXml, "escapeXml");
|
|
171401
|
-
__name(buildBackgroundTaskNotification, "buildBackgroundTaskNotification");
|
|
171402
|
-
}
|
|
171403
|
-
});
|
|
171404
|
-
|
|
171405
|
-
// packages/core/dist/src/utils/thoughtUtils.js
|
|
171406
|
-
function parseThought(rawText) {
|
|
171407
|
-
const startIndex = rawText.indexOf(START_DELIMITER);
|
|
171408
|
-
if (startIndex === -1) {
|
|
171409
|
-
return { subject: "", description: rawText };
|
|
171410
|
-
}
|
|
171411
|
-
const endIndex = rawText.indexOf(END_DELIMITER, startIndex + START_DELIMITER.length);
|
|
171412
|
-
if (endIndex === -1) {
|
|
171413
|
-
return { subject: "", description: rawText };
|
|
171414
|
-
}
|
|
171415
|
-
const subject = rawText.substring(startIndex + START_DELIMITER.length, endIndex).trim();
|
|
171416
|
-
const description = (rawText.substring(0, startIndex) + rawText.substring(endIndex + END_DELIMITER.length)).trim();
|
|
171417
|
-
return { subject, description };
|
|
171418
|
-
}
|
|
171419
|
-
function getThoughtText(response) {
|
|
171420
|
-
if (response.candidates && response.candidates.length > 0) {
|
|
171421
|
-
const candidate = response.candidates[0];
|
|
171422
|
-
if (candidate.content && candidate.content.parts && candidate.content.parts.length > 0) {
|
|
171423
|
-
return candidate.content.parts.filter((part) => part.thought && !isInternalPart(part)).map((part) => part.text ?? "").join("");
|
|
171424
|
-
}
|
|
171425
|
-
}
|
|
171426
|
-
return null;
|
|
171427
|
-
}
|
|
171428
|
-
var START_DELIMITER, END_DELIMITER;
|
|
171429
|
-
var init_thoughtUtils = __esm({
|
|
171430
|
-
"packages/core/dist/src/utils/thoughtUtils.js"() {
|
|
171431
|
-
"use strict";
|
|
171432
|
-
init_esbuild_shims();
|
|
171433
|
-
init_partUtils();
|
|
171434
|
-
START_DELIMITER = "**";
|
|
171435
|
-
END_DELIMITER = "**";
|
|
171436
|
-
__name(parseThought, "parseThought");
|
|
171437
|
-
__name(getThoughtText, "getThoughtText");
|
|
171438
|
-
}
|
|
171439
|
-
});
|
|
171440
|
-
|
|
171441
|
-
// packages/core/dist/src/utils/streamStall.js
|
|
171442
|
-
async function* withChunkTimeout(source2, timeoutMs) {
|
|
171443
|
-
while (true) {
|
|
171444
|
-
let timer;
|
|
171445
|
-
const stallPromise = new Promise((_2, reject) => {
|
|
171446
|
-
timer = setTimeout(() => reject(new StreamStallError(timeoutMs)), timeoutMs);
|
|
171447
|
-
});
|
|
171448
|
-
let result;
|
|
171449
|
-
try {
|
|
171450
|
-
result = await Promise.race([source2.next(), stallPromise]);
|
|
171451
|
-
clearTimeout(timer);
|
|
171452
|
-
} catch (err3) {
|
|
171453
|
-
clearTimeout(timer);
|
|
171454
|
-
try {
|
|
171455
|
-
void source2.return?.(void 0);
|
|
171456
|
-
} catch {
|
|
171457
|
-
}
|
|
171458
|
-
throw err3;
|
|
171459
|
-
}
|
|
171460
|
-
if (result.done)
|
|
171461
|
-
return;
|
|
171462
|
-
yield result.value;
|
|
171463
|
-
}
|
|
171464
|
-
}
|
|
171465
|
-
var StreamStallError;
|
|
171466
|
-
var init_streamStall = __esm({
|
|
171467
|
-
"packages/core/dist/src/utils/streamStall.js"() {
|
|
171468
|
-
"use strict";
|
|
171469
|
-
init_esbuild_shims();
|
|
171470
|
-
StreamStallError = class extends Error {
|
|
171471
|
-
static {
|
|
171472
|
-
__name(this, "StreamStallError");
|
|
171473
|
-
}
|
|
171474
|
-
timeoutMs;
|
|
171475
|
-
constructor(timeoutMs) {
|
|
171476
|
-
super(`Stream stalled: no data received for ${timeoutMs / 1e3}s. The model connection may have dropped \u2014 please try again.`);
|
|
171477
|
-
this.name = "StreamStallError";
|
|
171478
|
-
this.timeoutMs = timeoutMs;
|
|
171479
|
-
}
|
|
171480
|
-
};
|
|
171481
|
-
__name(withChunkTimeout, "withChunkTimeout");
|
|
171482
|
-
}
|
|
171483
|
-
});
|
|
171484
|
-
|
|
171485
|
-
// packages/core/dist/src/core/turn.js
|
|
171486
|
-
function getCitations(resp) {
|
|
171487
|
-
return (resp.candidates?.[0]?.citationMetadata?.citations ?? []).filter((citation) => citation.uri !== void 0).map((citation) => {
|
|
171488
|
-
if (citation.title) {
|
|
171489
|
-
return `(${citation.title}) ${citation.uri}`;
|
|
171490
|
-
}
|
|
171491
|
-
return citation.uri;
|
|
171492
|
-
});
|
|
171493
|
-
}
|
|
171494
|
-
var STREAM_STALL_TIMEOUT_MS, GeminiEventType, CompressionStatus, Turn;
|
|
171495
|
-
var init_turn = __esm({
|
|
171496
|
-
"packages/core/dist/src/core/turn.js"() {
|
|
171497
|
-
"use strict";
|
|
171498
|
-
init_esbuild_shims();
|
|
171499
|
-
init_node();
|
|
171500
|
-
init_partUtils();
|
|
171501
|
-
init_errorReporting();
|
|
171502
|
-
init_errors();
|
|
171503
|
-
init_thoughtUtils();
|
|
171504
|
-
init_streamStall();
|
|
171505
|
-
STREAM_STALL_TIMEOUT_MS = parseInt(process.env["PROTO_STREAM_STALL_TIMEOUT_MS"] ?? "300000", 10);
|
|
171506
|
-
(function(GeminiEventType2) {
|
|
171507
|
-
GeminiEventType2["Content"] = "content";
|
|
171508
|
-
GeminiEventType2["ToolCallRequest"] = "tool_call_request";
|
|
171509
|
-
GeminiEventType2["ToolCallResponse"] = "tool_call_response";
|
|
171510
|
-
GeminiEventType2["ToolCallConfirmation"] = "tool_call_confirmation";
|
|
171511
|
-
GeminiEventType2["UserCancelled"] = "user_cancelled";
|
|
171512
|
-
GeminiEventType2["Error"] = "error";
|
|
171513
|
-
GeminiEventType2["ChatCompressed"] = "chat_compressed";
|
|
171514
|
-
GeminiEventType2["Thought"] = "thought";
|
|
171515
|
-
GeminiEventType2["MaxSessionTurns"] = "max_session_turns";
|
|
171516
|
-
GeminiEventType2["SessionTokenLimitExceeded"] = "session_token_limit_exceeded";
|
|
171517
|
-
GeminiEventType2["Finished"] = "finished";
|
|
171518
|
-
GeminiEventType2["LoopDetected"] = "loop_detected";
|
|
171519
|
-
GeminiEventType2["Citation"] = "citation";
|
|
171520
|
-
GeminiEventType2["Retry"] = "retry";
|
|
171521
|
-
GeminiEventType2["HookSystemMessage"] = "hook_system_message";
|
|
171522
|
-
})(GeminiEventType || (GeminiEventType = {}));
|
|
171523
|
-
(function(CompressionStatus2) {
|
|
171524
|
-
CompressionStatus2[CompressionStatus2["COMPRESSED"] = 1] = "COMPRESSED";
|
|
171525
|
-
CompressionStatus2[CompressionStatus2["COMPRESSION_FAILED_INFLATED_TOKEN_COUNT"] = 2] = "COMPRESSION_FAILED_INFLATED_TOKEN_COUNT";
|
|
171526
|
-
CompressionStatus2[CompressionStatus2["COMPRESSION_FAILED_TOKEN_COUNT_ERROR"] = 3] = "COMPRESSION_FAILED_TOKEN_COUNT_ERROR";
|
|
171527
|
-
CompressionStatus2[CompressionStatus2["COMPRESSION_FAILED_EMPTY_SUMMARY"] = 4] = "COMPRESSION_FAILED_EMPTY_SUMMARY";
|
|
171528
|
-
CompressionStatus2[CompressionStatus2["NOOP"] = 5] = "NOOP";
|
|
171529
|
-
})(CompressionStatus || (CompressionStatus = {}));
|
|
171530
|
-
Turn = class {
|
|
171531
|
-
static {
|
|
171532
|
-
__name(this, "Turn");
|
|
171533
|
-
}
|
|
171534
|
-
chat;
|
|
171535
|
-
prompt_id;
|
|
171536
|
-
pendingToolCalls = [];
|
|
171537
|
-
debugResponses = [];
|
|
171538
|
-
pendingCitations = /* @__PURE__ */ new Set();
|
|
171539
|
-
finishReason = void 0;
|
|
171540
|
-
currentResponseId;
|
|
171541
|
-
constructor(chat, prompt_id) {
|
|
171542
|
-
this.chat = chat;
|
|
171543
|
-
this.prompt_id = prompt_id;
|
|
171544
|
-
}
|
|
171545
|
-
// The run method yields simpler events suitable for server logic
|
|
171546
|
-
async *run(model, req, signal) {
|
|
171547
|
-
try {
|
|
171548
|
-
const rawStream = await this.chat.sendMessageStream(model, {
|
|
171549
|
-
message: req,
|
|
171550
|
-
config: {
|
|
171551
|
-
abortSignal: signal
|
|
171552
|
-
}
|
|
171553
|
-
}, this.prompt_id);
|
|
171554
|
-
const responseStream = withChunkTimeout(rawStream, STREAM_STALL_TIMEOUT_MS);
|
|
171555
|
-
for await (const streamEvent of responseStream) {
|
|
171556
|
-
if (signal?.aborted) {
|
|
171557
|
-
yield { type: GeminiEventType.UserCancelled };
|
|
171558
|
-
return;
|
|
171559
|
-
}
|
|
171560
|
-
if (streamEvent.type === "retry") {
|
|
171561
|
-
yield {
|
|
171562
|
-
type: GeminiEventType.Retry,
|
|
171563
|
-
retryInfo: streamEvent.retryInfo
|
|
171564
|
-
};
|
|
171565
|
-
continue;
|
|
171566
|
-
}
|
|
171567
|
-
const resp = streamEvent.value;
|
|
171568
|
-
if (!resp)
|
|
171569
|
-
continue;
|
|
171570
|
-
this.debugResponses.push(resp);
|
|
171571
|
-
if (resp.responseId) {
|
|
171572
|
-
this.currentResponseId = resp.responseId;
|
|
171573
|
-
}
|
|
171574
|
-
const thoughtText = getThoughtText(resp);
|
|
171575
|
-
if (thoughtText) {
|
|
171576
|
-
yield {
|
|
171577
|
-
type: GeminiEventType.Thought,
|
|
171578
|
-
value: parseThought(thoughtText)
|
|
171579
|
-
};
|
|
171580
|
-
}
|
|
171581
|
-
const text = getResponseText(resp);
|
|
171582
|
-
if (text) {
|
|
171583
|
-
yield { type: GeminiEventType.Content, value: text };
|
|
171584
|
-
}
|
|
171585
|
-
const functionCalls = resp.functionCalls ?? [];
|
|
171586
|
-
for (const fnCall of functionCalls) {
|
|
171587
|
-
const event = this.handlePendingFunctionCall(fnCall);
|
|
171588
|
-
if (event) {
|
|
171589
|
-
yield event;
|
|
171590
|
-
}
|
|
171591
|
-
}
|
|
171592
|
-
for (const citation of getCitations(resp)) {
|
|
171593
|
-
this.pendingCitations.add(citation);
|
|
171594
|
-
}
|
|
171595
|
-
const finishReason = resp.candidates?.[0]?.finishReason;
|
|
171596
|
-
if (finishReason) {
|
|
171597
|
-
if (finishReason === FinishReason.MAX_TOKENS) {
|
|
171598
|
-
for (const tc of this.pendingToolCalls) {
|
|
171599
|
-
tc.wasOutputTruncated = true;
|
|
171600
|
-
}
|
|
171601
|
-
}
|
|
171602
|
-
if (this.pendingCitations.size > 0) {
|
|
171603
|
-
yield {
|
|
171604
|
-
type: GeminiEventType.Citation,
|
|
171605
|
-
value: `Citations:
|
|
171606
|
-
${[...this.pendingCitations].sort().join("\n")}`
|
|
171607
|
-
};
|
|
171608
|
-
this.pendingCitations.clear();
|
|
171609
|
-
}
|
|
171610
|
-
this.finishReason = finishReason;
|
|
171611
|
-
yield {
|
|
171612
|
-
type: GeminiEventType.Finished,
|
|
171613
|
-
value: {
|
|
171614
|
-
reason: finishReason,
|
|
171615
|
-
usageMetadata: resp.usageMetadata
|
|
171616
|
-
}
|
|
171617
|
-
};
|
|
171618
|
-
}
|
|
171619
|
-
}
|
|
171620
|
-
} catch (e4) {
|
|
171621
|
-
if (signal.aborted) {
|
|
171622
|
-
yield { type: GeminiEventType.UserCancelled };
|
|
171623
|
-
return;
|
|
171624
|
-
}
|
|
171625
|
-
if (e4 instanceof StreamStallError) {
|
|
171626
|
-
yield {
|
|
171627
|
-
type: GeminiEventType.Error,
|
|
171628
|
-
value: {
|
|
171629
|
-
error: {
|
|
171630
|
-
message: e4.message,
|
|
171631
|
-
status: void 0
|
|
171632
|
-
}
|
|
171633
|
-
}
|
|
171634
|
-
};
|
|
171635
|
-
return;
|
|
171636
|
-
}
|
|
171637
|
-
const error40 = toFriendlyError(e4);
|
|
171638
|
-
if (error40 instanceof UnauthorizedError) {
|
|
171639
|
-
throw error40;
|
|
171640
|
-
}
|
|
171641
|
-
const contextForReport = [...this.chat.getHistory(
|
|
171642
|
-
/*curated*/
|
|
171643
|
-
true
|
|
171644
|
-
), req];
|
|
171645
|
-
await reportError2(error40, "Error when talking to API", contextForReport, "Turn.run-sendMessageStream");
|
|
171646
|
-
const status = typeof error40 === "object" && error40 !== null && "status" in error40 && typeof error40.status === "number" ? error40.status : void 0;
|
|
171647
|
-
const structuredError = {
|
|
171648
|
-
message: getErrorMessage(error40),
|
|
171649
|
-
status
|
|
171650
|
-
};
|
|
171651
|
-
await this.chat.maybeIncludeSchemaDepthContext(structuredError);
|
|
171652
|
-
yield { type: GeminiEventType.Error, value: { error: structuredError } };
|
|
171653
|
-
return;
|
|
171654
|
-
}
|
|
171655
|
-
}
|
|
171656
|
-
handlePendingFunctionCall(fnCall) {
|
|
171657
|
-
const callId = fnCall.id ?? `${fnCall.name}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
171658
|
-
const name4 = fnCall.name || "undefined_tool_name";
|
|
171659
|
-
const args2 = fnCall.args || {};
|
|
171660
|
-
const toolCallRequest = {
|
|
171661
|
-
callId,
|
|
171662
|
-
name: name4,
|
|
171663
|
-
args: args2,
|
|
171664
|
-
isClientInitiated: false,
|
|
171665
|
-
prompt_id: this.prompt_id,
|
|
171666
|
-
response_id: this.currentResponseId
|
|
171667
|
-
};
|
|
171668
|
-
this.pendingToolCalls.push(toolCallRequest);
|
|
171669
|
-
return { type: GeminiEventType.ToolCallRequest, value: toolCallRequest };
|
|
171670
|
-
}
|
|
171671
|
-
getDebugResponses() {
|
|
171672
|
-
return this.debugResponses;
|
|
171673
|
-
}
|
|
171674
|
-
};
|
|
171675
|
-
__name(getCitations, "getCitations");
|
|
171676
|
-
}
|
|
171677
|
-
});
|
|
171678
|
-
|
|
171679
170534
|
// packages/core/dist/src/hooks/types.js
|
|
171680
170535
|
function getHookKey(hook) {
|
|
171681
170536
|
const name4 = hook.name ?? "";
|
|
@@ -171710,13 +170565,13 @@ function createHookOutput(eventName, data) {
|
|
|
171710
170565
|
return new DefaultHookOutput(data);
|
|
171711
170566
|
}
|
|
171712
170567
|
}
|
|
171713
|
-
var
|
|
170568
|
+
var debugLogger22, HooksConfigSource, HookEventName, HOOKS_CONFIG_FIELDS, HookType, DefaultHookOutput, PreToolUseHookOutput, PostToolUseHookOutput, PostToolUseFailureHookOutput, StopHookOutput, PermissionRequestHookOutput, NotificationType, SessionStartSource, PermissionMode, SessionEndReason, PreCompactTrigger, AgentType;
|
|
171714
170569
|
var init_types6 = __esm({
|
|
171715
170570
|
"packages/core/dist/src/hooks/types.js"() {
|
|
171716
170571
|
"use strict";
|
|
171717
170572
|
init_esbuild_shims();
|
|
171718
170573
|
init_debugLogger();
|
|
171719
|
-
|
|
170574
|
+
debugLogger22 = createDebugLogger("TRUSTED_HOOKS");
|
|
171720
170575
|
(function(HooksConfigSource2) {
|
|
171721
170576
|
HooksConfigSource2["Project"] = "project";
|
|
171722
170577
|
HooksConfigSource2["User"] = "user";
|
|
@@ -171888,10 +170743,10 @@ var init_types6 = __esm({
|
|
|
171888
170743
|
this.decision = data.decision ?? "allow";
|
|
171889
170744
|
this.reason = data.reason ?? "No reason provided";
|
|
171890
170745
|
if (data.decision === void 0) {
|
|
171891
|
-
|
|
170746
|
+
debugLogger22.debug('PostToolUseHookOutput: No explicit decision set, defaulting to "allow"');
|
|
171892
170747
|
}
|
|
171893
170748
|
if (data.reason === void 0) {
|
|
171894
|
-
|
|
170749
|
+
debugLogger22.debug('PostToolUseHookOutput: No explicit reason set, defaulting to "No reason provided"');
|
|
171895
170750
|
}
|
|
171896
170751
|
}
|
|
171897
170752
|
};
|
|
@@ -172026,30 +170881,30 @@ __export(sessionNotes_exports, {
|
|
|
172026
170881
|
readSessionNotes: () => readSessionNotes,
|
|
172027
170882
|
updateSessionNoteSection: () => updateSessionNoteSection
|
|
172028
170883
|
});
|
|
172029
|
-
import * as
|
|
172030
|
-
import * as
|
|
170884
|
+
import * as fs19 from "node:fs/promises";
|
|
170885
|
+
import * as path18 from "node:path";
|
|
172031
170886
|
function getSessionNotesPath(projectDir) {
|
|
172032
|
-
return
|
|
170887
|
+
return path18.join(projectDir, ".proto", SESSION_NOTES_FILENAME);
|
|
172033
170888
|
}
|
|
172034
170889
|
async function readSessionNotes(projectDir) {
|
|
172035
170890
|
const filePath = getSessionNotesPath(projectDir);
|
|
172036
170891
|
try {
|
|
172037
|
-
return await
|
|
170892
|
+
return await fs19.readFile(filePath, "utf-8");
|
|
172038
170893
|
} catch {
|
|
172039
170894
|
return null;
|
|
172040
170895
|
}
|
|
172041
170896
|
}
|
|
172042
170897
|
async function initSessionNotes(projectDir) {
|
|
172043
170898
|
const filePath = getSessionNotesPath(projectDir);
|
|
172044
|
-
await
|
|
172045
|
-
await
|
|
170899
|
+
await fs19.mkdir(path18.dirname(filePath), { recursive: true });
|
|
170900
|
+
await fs19.writeFile(filePath, SESSION_NOTES_TEMPLATE, "utf-8");
|
|
172046
170901
|
logger2.debug("Session notes initialized");
|
|
172047
170902
|
}
|
|
172048
170903
|
async function updateSessionNoteSection(projectDir, section, content) {
|
|
172049
170904
|
const filePath = getSessionNotesPath(projectDir);
|
|
172050
170905
|
let raw2;
|
|
172051
170906
|
try {
|
|
172052
|
-
raw2 = await
|
|
170907
|
+
raw2 = await fs19.readFile(filePath, "utf-8");
|
|
172053
170908
|
} catch {
|
|
172054
170909
|
raw2 = SESSION_NOTES_TEMPLATE;
|
|
172055
170910
|
}
|
|
@@ -172072,8 +170927,8 @@ async function updateSessionNoteSection(projectDir, section, content) {
|
|
|
172072
170927
|
const updated = `${before}
|
|
172073
170928
|
${content.trim()}
|
|
172074
170929
|
${after}`;
|
|
172075
|
-
await
|
|
172076
|
-
await
|
|
170930
|
+
await fs19.mkdir(path18.dirname(filePath), { recursive: true });
|
|
170931
|
+
await fs19.writeFile(filePath, updated, "utf-8");
|
|
172077
170932
|
}
|
|
172078
170933
|
async function clearSessionNotes(projectDir) {
|
|
172079
170934
|
await initSessionNotes(projectDir);
|
|
@@ -172423,494 +171278,1817 @@ function applyMicrocompact(history, verbatimWindowSize = INCREMENTAL_PROTECTED_T
|
|
|
172423
171278
|
...part.functionResponse,
|
|
172424
171279
|
response: { output: MICROCOMPACT_STUB }
|
|
172425
171280
|
}
|
|
172426
|
-
};
|
|
172427
|
-
});
|
|
172428
|
-
return { ...msg, parts: newParts };
|
|
172429
|
-
});
|
|
172430
|
-
return { newHistory, clearedCount };
|
|
172431
|
-
}
|
|
172432
|
-
function estimateMicrocompactSaving(history, verbatimWindowSize = INCREMENTAL_PROTECTED_TAIL) {
|
|
172433
|
-
const original = JSON.stringify(history).length;
|
|
172434
|
-
if (original === 0)
|
|
172435
|
-
return 0;
|
|
172436
|
-
const { newHistory } = applyMicrocompact(history, verbatimWindowSize);
|
|
172437
|
-
const compacted = JSON.stringify(newHistory).length;
|
|
172438
|
-
return Math.max(0, (original - compacted) / original);
|
|
172439
|
-
}
|
|
172440
|
-
var MICROCOMPACT_STUB;
|
|
172441
|
-
var init_microcompact = __esm({
|
|
172442
|
-
"packages/core/dist/src/services/microcompact.js"() {
|
|
172443
|
-
"use strict";
|
|
172444
|
-
init_esbuild_shims();
|
|
172445
|
-
init_chatCompressionService();
|
|
172446
|
-
MICROCOMPACT_STUB = "[result cleared \u2014 see session notes for context]";
|
|
172447
|
-
__name(applyMicrocompact, "applyMicrocompact");
|
|
172448
|
-
__name(estimateMicrocompactSaving, "estimateMicrocompactSaving");
|
|
171281
|
+
};
|
|
171282
|
+
});
|
|
171283
|
+
return { ...msg, parts: newParts };
|
|
171284
|
+
});
|
|
171285
|
+
return { newHistory, clearedCount };
|
|
171286
|
+
}
|
|
171287
|
+
function estimateMicrocompactSaving(history, verbatimWindowSize = INCREMENTAL_PROTECTED_TAIL) {
|
|
171288
|
+
const original = JSON.stringify(history).length;
|
|
171289
|
+
if (original === 0)
|
|
171290
|
+
return 0;
|
|
171291
|
+
const { newHistory } = applyMicrocompact(history, verbatimWindowSize);
|
|
171292
|
+
const compacted = JSON.stringify(newHistory).length;
|
|
171293
|
+
return Math.max(0, (original - compacted) / original);
|
|
171294
|
+
}
|
|
171295
|
+
var MICROCOMPACT_STUB;
|
|
171296
|
+
var init_microcompact = __esm({
|
|
171297
|
+
"packages/core/dist/src/services/microcompact.js"() {
|
|
171298
|
+
"use strict";
|
|
171299
|
+
init_esbuild_shims();
|
|
171300
|
+
init_chatCompressionService();
|
|
171301
|
+
MICROCOMPACT_STUB = "[result cleared \u2014 see session notes for context]";
|
|
171302
|
+
__name(applyMicrocompact, "applyMicrocompact");
|
|
171303
|
+
__name(estimateMicrocompactSaving, "estimateMicrocompactSaving");
|
|
171304
|
+
}
|
|
171305
|
+
});
|
|
171306
|
+
|
|
171307
|
+
// packages/core/dist/src/services/chatCompressionService.js
|
|
171308
|
+
function applyObservationMask(history, verbatimWindowSize = INCREMENTAL_PROTECTED_TAIL) {
|
|
171309
|
+
if (history.length <= verbatimWindowSize)
|
|
171310
|
+
return history;
|
|
171311
|
+
let pairsKept = 0;
|
|
171312
|
+
let cutIndex = history.length;
|
|
171313
|
+
for (let i4 = history.length - 1; i4 >= 0; i4--) {
|
|
171314
|
+
const msg = history[i4];
|
|
171315
|
+
if (msg?.role === "user" && msg.parts?.some((p2) => p2.functionResponse)) {
|
|
171316
|
+
pairsKept++;
|
|
171317
|
+
if (pairsKept >= verbatimWindowSize) {
|
|
171318
|
+
cutIndex = i4;
|
|
171319
|
+
break;
|
|
171320
|
+
}
|
|
171321
|
+
}
|
|
171322
|
+
}
|
|
171323
|
+
if (cutIndex === 0)
|
|
171324
|
+
return history;
|
|
171325
|
+
const maskedCount = history.slice(0, cutIndex).filter((m3) => m3.role === "user" && m3.parts?.some((p2) => p2.functionResponse) || m3.role === "model" && m3.parts?.some((p2) => p2.functionCall)).length;
|
|
171326
|
+
const placeholder = {
|
|
171327
|
+
role: "user",
|
|
171328
|
+
parts: [
|
|
171329
|
+
{
|
|
171330
|
+
text: `[OBSERVATION_MASK: ${maskedCount} tool call/result pairs from earlier in the session have been masked to reduce context. The most recent ${verbatimWindowSize} pairs are preserved verbatim below.]`
|
|
171331
|
+
}
|
|
171332
|
+
]
|
|
171333
|
+
};
|
|
171334
|
+
return [placeholder, ...history.slice(cutIndex)];
|
|
171335
|
+
}
|
|
171336
|
+
function extractContentText(content) {
|
|
171337
|
+
if (!content.parts || content.parts.length === 0) {
|
|
171338
|
+
return null;
|
|
171339
|
+
}
|
|
171340
|
+
const texts = content.parts.filter((part) => part.text !== void 0).map((part) => part.text);
|
|
171341
|
+
if (texts.length === 0) {
|
|
171342
|
+
return null;
|
|
171343
|
+
}
|
|
171344
|
+
return texts.join("");
|
|
171345
|
+
}
|
|
171346
|
+
function isCompressedMessage(content) {
|
|
171347
|
+
const text = extractContentText(content);
|
|
171348
|
+
return text !== null && text.startsWith(COMPRESSED_CONTEXT_PREFIX);
|
|
171349
|
+
}
|
|
171350
|
+
function findCompressSplitPoint(contents, fraction) {
|
|
171351
|
+
if (fraction <= 0 || fraction >= 1) {
|
|
171352
|
+
throw new Error("Fraction must be between 0 and 1");
|
|
171353
|
+
}
|
|
171354
|
+
const charCounts = contents.map((content) => JSON.stringify(content).length);
|
|
171355
|
+
const totalCharCount = charCounts.reduce((a2, b2) => a2 + b2, 0);
|
|
171356
|
+
const targetCharCount = totalCharCount * fraction;
|
|
171357
|
+
let lastSplitPoint = 0;
|
|
171358
|
+
let cumulativeCharCount = 0;
|
|
171359
|
+
for (let i4 = 0; i4 < contents.length; i4++) {
|
|
171360
|
+
const content = contents[i4];
|
|
171361
|
+
if (content.role === "user" && !content.parts?.some((part) => !!part.functionResponse)) {
|
|
171362
|
+
if (cumulativeCharCount >= targetCharCount) {
|
|
171363
|
+
return i4;
|
|
171364
|
+
}
|
|
171365
|
+
lastSplitPoint = i4;
|
|
171366
|
+
}
|
|
171367
|
+
cumulativeCharCount += charCounts[i4];
|
|
171368
|
+
}
|
|
171369
|
+
const lastContent = contents[contents.length - 1];
|
|
171370
|
+
if (lastContent?.role === "model" && !lastContent?.parts?.some((part) => part.functionCall)) {
|
|
171371
|
+
return contents.length;
|
|
171372
|
+
}
|
|
171373
|
+
if (lastContent?.role === "user" && lastContent?.parts?.some((part) => !!part.functionResponse)) {
|
|
171374
|
+
return contents.length;
|
|
171375
|
+
}
|
|
171376
|
+
return lastSplitPoint;
|
|
171377
|
+
}
|
|
171378
|
+
function estimateHistoryTokens(history) {
|
|
171379
|
+
return Math.ceil(history.reduce((sum, entry) => sum + JSON.stringify(entry).length, 0) / 4);
|
|
171380
|
+
}
|
|
171381
|
+
function adjustIndexForToolPairs(history, startIndex) {
|
|
171382
|
+
let idx = startIndex;
|
|
171383
|
+
while (idx > 0) {
|
|
171384
|
+
const msg = history[idx];
|
|
171385
|
+
if (!msg)
|
|
171386
|
+
break;
|
|
171387
|
+
const isUserWithNoResponse = msg.role === "user" && !(msg.parts ?? []).some((p2) => "functionResponse" in p2);
|
|
171388
|
+
const isModelWithNoCall = msg.role === "model" && !(msg.parts ?? []).some((p2) => "functionCall" in p2);
|
|
171389
|
+
if (isUserWithNoResponse || isModelWithNoCall)
|
|
171390
|
+
break;
|
|
171391
|
+
idx--;
|
|
171392
|
+
}
|
|
171393
|
+
return idx;
|
|
171394
|
+
}
|
|
171395
|
+
var COMPRESSION_TOKEN_THRESHOLD, COMPRESSION_PRESERVE_THRESHOLD, INCREMENTAL_PROTECTED_TAIL, INCREMENTAL_MAX_CHUNK_SIZE, COMPRESSED_CONTEXT_PREFIX, MIN_COMPRESSION_FRACTION, ChatCompressionService;
|
|
171396
|
+
var init_chatCompressionService = __esm({
|
|
171397
|
+
"packages/core/dist/src/services/chatCompressionService.js"() {
|
|
171398
|
+
"use strict";
|
|
171399
|
+
init_esbuild_shims();
|
|
171400
|
+
init_turn();
|
|
171401
|
+
init_uiTelemetry();
|
|
171402
|
+
init_tokenLimits();
|
|
171403
|
+
init_prompts();
|
|
171404
|
+
init_partUtils();
|
|
171405
|
+
init_loggers();
|
|
171406
|
+
init_types4();
|
|
171407
|
+
init_types6();
|
|
171408
|
+
init_sessionNotes();
|
|
171409
|
+
init_sessionMemoryUtils();
|
|
171410
|
+
init_prompts2();
|
|
171411
|
+
init_microcompact();
|
|
171412
|
+
COMPRESSION_TOKEN_THRESHOLD = 0.7;
|
|
171413
|
+
COMPRESSION_PRESERVE_THRESHOLD = 0.3;
|
|
171414
|
+
INCREMENTAL_PROTECTED_TAIL = 10;
|
|
171415
|
+
INCREMENTAL_MAX_CHUNK_SIZE = 20;
|
|
171416
|
+
COMPRESSED_CONTEXT_PREFIX = "[COMPRESSED_CONTEXT]";
|
|
171417
|
+
MIN_COMPRESSION_FRACTION = 0.05;
|
|
171418
|
+
__name(applyObservationMask, "applyObservationMask");
|
|
171419
|
+
__name(extractContentText, "extractContentText");
|
|
171420
|
+
__name(isCompressedMessage, "isCompressedMessage");
|
|
171421
|
+
__name(findCompressSplitPoint, "findCompressSplitPoint");
|
|
171422
|
+
ChatCompressionService = class {
|
|
171423
|
+
static {
|
|
171424
|
+
__name(this, "ChatCompressionService");
|
|
171425
|
+
}
|
|
171426
|
+
async compress(chat, promptId, force, model, config2, hasFailedCompressionAttempt, signal) {
|
|
171427
|
+
const curatedHistory = chat.getHistory(true);
|
|
171428
|
+
const threshold = config2.getChatCompression()?.contextPercentageThreshold ?? COMPRESSION_TOKEN_THRESHOLD;
|
|
171429
|
+
if (curatedHistory.length === 0 || threshold <= 0 || hasFailedCompressionAttempt && !force) {
|
|
171430
|
+
return {
|
|
171431
|
+
newHistory: null,
|
|
171432
|
+
info: {
|
|
171433
|
+
originalTokenCount: 0,
|
|
171434
|
+
newTokenCount: 0,
|
|
171435
|
+
compressionStatus: CompressionStatus.NOOP
|
|
171436
|
+
}
|
|
171437
|
+
};
|
|
171438
|
+
}
|
|
171439
|
+
const originalTokenCount = uiTelemetryService.getLastPromptTokenCount();
|
|
171440
|
+
if (!force) {
|
|
171441
|
+
const contextLimit = config2.getContentGeneratorConfig()?.contextWindowSize ?? DEFAULT_TOKEN_LIMIT;
|
|
171442
|
+
if (originalTokenCount < threshold * contextLimit) {
|
|
171443
|
+
return {
|
|
171444
|
+
newHistory: null,
|
|
171445
|
+
info: {
|
|
171446
|
+
originalTokenCount,
|
|
171447
|
+
newTokenCount: originalTokenCount,
|
|
171448
|
+
compressionStatus: CompressionStatus.NOOP
|
|
171449
|
+
}
|
|
171450
|
+
};
|
|
171451
|
+
}
|
|
171452
|
+
}
|
|
171453
|
+
if (!force) {
|
|
171454
|
+
const smResult = await this.trySessionMemoryCompaction(curatedHistory, originalTokenCount, config2);
|
|
171455
|
+
if (smResult)
|
|
171456
|
+
return smResult;
|
|
171457
|
+
}
|
|
171458
|
+
if (!force) {
|
|
171459
|
+
const saving = estimateMicrocompactSaving(curatedHistory);
|
|
171460
|
+
if (saving >= 0.2) {
|
|
171461
|
+
const { newHistory: microHistory } = applyMicrocompact(curatedHistory);
|
|
171462
|
+
const newTokenCount = Math.round(originalTokenCount * (1 - saving));
|
|
171463
|
+
uiTelemetryService.setLastPromptTokenCount(newTokenCount);
|
|
171464
|
+
return {
|
|
171465
|
+
newHistory: microHistory,
|
|
171466
|
+
info: {
|
|
171467
|
+
originalTokenCount,
|
|
171468
|
+
newTokenCount,
|
|
171469
|
+
compressionStatus: CompressionStatus.COMPRESSED
|
|
171470
|
+
}
|
|
171471
|
+
};
|
|
171472
|
+
}
|
|
171473
|
+
}
|
|
171474
|
+
const hookSystem = config2.getHookSystem();
|
|
171475
|
+
if (hookSystem) {
|
|
171476
|
+
const trigger = force ? PreCompactTrigger.Manual : PreCompactTrigger.Auto;
|
|
171477
|
+
try {
|
|
171478
|
+
await hookSystem.firePreCompactEvent(trigger, "", signal);
|
|
171479
|
+
} catch (err3) {
|
|
171480
|
+
config2.getDebugLogger().warn(`PreCompact hook failed: ${err3}`);
|
|
171481
|
+
}
|
|
171482
|
+
}
|
|
171483
|
+
const incrementalResult = await this.compressIncremental(curatedHistory, model, config2, promptId, signal);
|
|
171484
|
+
if (incrementalResult.compressed) {
|
|
171485
|
+
return this.finalizeCompression(incrementalResult.newHistory, originalTokenCount, incrementalResult.compressionInputTokenCount, incrementalResult.compressionOutputTokenCount, model, config2, signal);
|
|
171486
|
+
}
|
|
171487
|
+
return this.compressFull(curatedHistory, originalTokenCount, model, config2, promptId, force, signal);
|
|
171488
|
+
}
|
|
171489
|
+
/**
|
|
171490
|
+
* Incremental compression: protects the most recent messages and compresses
|
|
171491
|
+
* the oldest uncompressed chunk. Each call compresses one chunk, making the
|
|
171492
|
+
* operation idempotent and safe to call repeatedly.
|
|
171493
|
+
*/
|
|
171494
|
+
async compressIncremental(history, model, config2, promptId, _signal) {
|
|
171495
|
+
const protectedTailMessages = INCREMENTAL_PROTECTED_TAIL;
|
|
171496
|
+
const maxChunkSize = INCREMENTAL_MAX_CHUNK_SIZE;
|
|
171497
|
+
if (history.length <= protectedTailMessages + 2) {
|
|
171498
|
+
return { newHistory: history, compressed: false };
|
|
171499
|
+
}
|
|
171500
|
+
const compressibleEnd = history.length - protectedTailMessages;
|
|
171501
|
+
let chunkStart = 0;
|
|
171502
|
+
while (chunkStart < compressibleEnd) {
|
|
171503
|
+
if (isCompressedMessage(history[chunkStart])) {
|
|
171504
|
+
chunkStart++;
|
|
171505
|
+
} else {
|
|
171506
|
+
break;
|
|
171507
|
+
}
|
|
171508
|
+
}
|
|
171509
|
+
if (chunkStart >= compressibleEnd) {
|
|
171510
|
+
return { newHistory: history, compressed: false };
|
|
171511
|
+
}
|
|
171512
|
+
const chunkEnd = Math.min(chunkStart + maxChunkSize, compressibleEnd);
|
|
171513
|
+
const chunk = history.slice(chunkStart, chunkEnd);
|
|
171514
|
+
const summaryResponse = await config2.getContentGenerator().generateContent({
|
|
171515
|
+
model,
|
|
171516
|
+
contents: [
|
|
171517
|
+
...chunk,
|
|
171518
|
+
{
|
|
171519
|
+
role: "user",
|
|
171520
|
+
parts: [
|
|
171521
|
+
{
|
|
171522
|
+
text: "Compress the conversation chunk above into a dense summary following the output format."
|
|
171523
|
+
}
|
|
171524
|
+
]
|
|
171525
|
+
}
|
|
171526
|
+
],
|
|
171527
|
+
config: {
|
|
171528
|
+
systemInstruction: getIncrementalCompressionPrompt()
|
|
171529
|
+
}
|
|
171530
|
+
}, promptId);
|
|
171531
|
+
const summary = getResponseText(summaryResponse) ?? "";
|
|
171532
|
+
if (!summary || summary.trim().length === 0) {
|
|
171533
|
+
return { newHistory: history, compressed: false };
|
|
171534
|
+
}
|
|
171535
|
+
const prefixedSummary = summary.startsWith(COMPRESSED_CONTEXT_PREFIX) ? summary : `${COMPRESSED_CONTEXT_PREFIX}
|
|
171536
|
+
${summary}`;
|
|
171537
|
+
const usageMetadata = summaryResponse.usageMetadata;
|
|
171538
|
+
const inputTokenCount = usageMetadata?.promptTokenCount;
|
|
171539
|
+
let outputTokenCount = usageMetadata?.candidatesTokenCount;
|
|
171540
|
+
if (outputTokenCount === void 0 && typeof usageMetadata?.totalTokenCount === "number" && typeof inputTokenCount === "number") {
|
|
171541
|
+
outputTokenCount = Math.max(0, usageMetadata.totalTokenCount - inputTokenCount);
|
|
171542
|
+
}
|
|
171543
|
+
const summaryMessage = {
|
|
171544
|
+
role: "user",
|
|
171545
|
+
parts: [{ text: prefixedSummary }]
|
|
171546
|
+
};
|
|
171547
|
+
const summaryAck = {
|
|
171548
|
+
role: "model",
|
|
171549
|
+
parts: [{ text: "Understood. Incremental context loaded." }]
|
|
171550
|
+
};
|
|
171551
|
+
const newHistory = [
|
|
171552
|
+
...history.slice(0, chunkStart),
|
|
171553
|
+
summaryMessage,
|
|
171554
|
+
summaryAck,
|
|
171555
|
+
...history.slice(chunkEnd)
|
|
171556
|
+
];
|
|
171557
|
+
return {
|
|
171558
|
+
newHistory,
|
|
171559
|
+
compressed: true,
|
|
171560
|
+
compressionInputTokenCount: inputTokenCount,
|
|
171561
|
+
compressionOutputTokenCount: outputTokenCount
|
|
171562
|
+
};
|
|
171563
|
+
}
|
|
171564
|
+
/**
|
|
171565
|
+
* Original full-history compression using getCompressionPrompt().
|
|
171566
|
+
* Used as a fallback when history is too short for incremental compression.
|
|
171567
|
+
*/
|
|
171568
|
+
async compressFull(curatedHistory, originalTokenCount, model, config2, promptId, force, signal) {
|
|
171569
|
+
const lastMessage = curatedHistory[curatedHistory.length - 1];
|
|
171570
|
+
const hasOrphanedFuncCall = force && lastMessage?.role === "model" && lastMessage.parts?.some((p2) => !!p2.functionCall);
|
|
171571
|
+
const historyForSplit = hasOrphanedFuncCall ? curatedHistory.slice(0, -1) : curatedHistory;
|
|
171572
|
+
const splitPoint = findCompressSplitPoint(historyForSplit, 1 - COMPRESSION_PRESERVE_THRESHOLD);
|
|
171573
|
+
const historyToCompress = historyForSplit.slice(0, splitPoint);
|
|
171574
|
+
const historyToKeep = historyForSplit.slice(splitPoint);
|
|
171575
|
+
if (historyToCompress.length === 0) {
|
|
171576
|
+
return {
|
|
171577
|
+
newHistory: null,
|
|
171578
|
+
info: {
|
|
171579
|
+
originalTokenCount,
|
|
171580
|
+
newTokenCount: originalTokenCount,
|
|
171581
|
+
compressionStatus: CompressionStatus.NOOP
|
|
171582
|
+
}
|
|
171583
|
+
};
|
|
171584
|
+
}
|
|
171585
|
+
const compressCharCount = historyToCompress.reduce((sum, c4) => sum + JSON.stringify(c4).length, 0);
|
|
171586
|
+
const totalCharCount = historyForSplit.reduce((sum, c4) => sum + JSON.stringify(c4).length, 0);
|
|
171587
|
+
if (totalCharCount > 0 && compressCharCount / totalCharCount < MIN_COMPRESSION_FRACTION) {
|
|
171588
|
+
return {
|
|
171589
|
+
newHistory: null,
|
|
171590
|
+
info: {
|
|
171591
|
+
originalTokenCount,
|
|
171592
|
+
newTokenCount: originalTokenCount,
|
|
171593
|
+
compressionStatus: CompressionStatus.NOOP
|
|
171594
|
+
}
|
|
171595
|
+
};
|
|
171596
|
+
}
|
|
171597
|
+
const summaryResponse = await config2.getContentGenerator().generateContent({
|
|
171598
|
+
model,
|
|
171599
|
+
contents: [
|
|
171600
|
+
...historyToCompress,
|
|
171601
|
+
{
|
|
171602
|
+
role: "user",
|
|
171603
|
+
parts: [
|
|
171604
|
+
{
|
|
171605
|
+
text: "Generate the <summary> now. Be maximally concise \u2014 every token counts."
|
|
171606
|
+
}
|
|
171607
|
+
]
|
|
171608
|
+
}
|
|
171609
|
+
],
|
|
171610
|
+
config: {
|
|
171611
|
+
systemInstruction: getCompressionPrompt()
|
|
171612
|
+
}
|
|
171613
|
+
}, promptId);
|
|
171614
|
+
const summary = getResponseText(summaryResponse) ?? "";
|
|
171615
|
+
const prefixedSummary = summary && summary.trim().length > 0 ? summary.startsWith(COMPRESSED_CONTEXT_PREFIX) ? summary : `${COMPRESSED_CONTEXT_PREFIX}
|
|
171616
|
+
${summary}` : summary;
|
|
171617
|
+
const compressionUsageMetadata = summaryResponse.usageMetadata;
|
|
171618
|
+
const compressionInputTokenCount = compressionUsageMetadata?.promptTokenCount;
|
|
171619
|
+
let compressionOutputTokenCount = compressionUsageMetadata?.candidatesTokenCount;
|
|
171620
|
+
if (compressionOutputTokenCount === void 0 && typeof compressionUsageMetadata?.totalTokenCount === "number" && typeof compressionInputTokenCount === "number") {
|
|
171621
|
+
compressionOutputTokenCount = Math.max(0, compressionUsageMetadata.totalTokenCount - compressionInputTokenCount);
|
|
171622
|
+
}
|
|
171623
|
+
const isSummaryEmpty = !prefixedSummary || prefixedSummary.trim().length === 0;
|
|
171624
|
+
let extraHistory = [];
|
|
171625
|
+
if (!isSummaryEmpty) {
|
|
171626
|
+
extraHistory = [
|
|
171627
|
+
{
|
|
171628
|
+
role: "user",
|
|
171629
|
+
parts: [{ text: prefixedSummary }]
|
|
171630
|
+
},
|
|
171631
|
+
{
|
|
171632
|
+
role: "model",
|
|
171633
|
+
parts: [{ text: "Got it. Thanks for the additional context!" }]
|
|
171634
|
+
},
|
|
171635
|
+
...historyToKeep
|
|
171636
|
+
];
|
|
171637
|
+
}
|
|
171638
|
+
return this.finalizeCompression(isSummaryEmpty ? null : extraHistory, originalTokenCount, compressionInputTokenCount, compressionOutputTokenCount, model, config2, signal, isSummaryEmpty);
|
|
171639
|
+
}
|
|
171640
|
+
/**
|
|
171641
|
+
* Shared finalization logic for both incremental and full compression.
|
|
171642
|
+
* Handles token math, telemetry, hook firing, and status determination.
|
|
171643
|
+
*/
|
|
171644
|
+
async finalizeCompression(newHistory, originalTokenCount, compressionInputTokenCount, compressionOutputTokenCount, model, config2, signal, isSummaryEmpty = false) {
|
|
171645
|
+
let newTokenCount = originalTokenCount;
|
|
171646
|
+
let canCalculateNewTokenCount = false;
|
|
171647
|
+
if (!isSummaryEmpty && newHistory) {
|
|
171648
|
+
if (typeof compressionInputTokenCount === "number" && compressionInputTokenCount > 0 && typeof compressionOutputTokenCount === "number" && compressionOutputTokenCount > 0) {
|
|
171649
|
+
canCalculateNewTokenCount = true;
|
|
171650
|
+
newTokenCount = Math.max(0, originalTokenCount - (compressionInputTokenCount - 1e3) + compressionOutputTokenCount);
|
|
171651
|
+
}
|
|
171652
|
+
}
|
|
171653
|
+
logChatCompression(config2, makeChatCompressionEvent({
|
|
171654
|
+
tokens_before: originalTokenCount,
|
|
171655
|
+
tokens_after: newTokenCount,
|
|
171656
|
+
compression_input_token_count: compressionInputTokenCount,
|
|
171657
|
+
compression_output_token_count: compressionOutputTokenCount
|
|
171658
|
+
}));
|
|
171659
|
+
if (isSummaryEmpty) {
|
|
171660
|
+
return {
|
|
171661
|
+
newHistory: null,
|
|
171662
|
+
info: {
|
|
171663
|
+
originalTokenCount,
|
|
171664
|
+
newTokenCount: originalTokenCount,
|
|
171665
|
+
compressionStatus: CompressionStatus.COMPRESSION_FAILED_EMPTY_SUMMARY
|
|
171666
|
+
}
|
|
171667
|
+
};
|
|
171668
|
+
} else if (!canCalculateNewTokenCount) {
|
|
171669
|
+
return {
|
|
171670
|
+
newHistory: null,
|
|
171671
|
+
info: {
|
|
171672
|
+
originalTokenCount,
|
|
171673
|
+
newTokenCount: originalTokenCount,
|
|
171674
|
+
compressionStatus: CompressionStatus.COMPRESSION_FAILED_TOKEN_COUNT_ERROR
|
|
171675
|
+
}
|
|
171676
|
+
};
|
|
171677
|
+
} else if (newTokenCount > originalTokenCount) {
|
|
171678
|
+
return {
|
|
171679
|
+
newHistory: null,
|
|
171680
|
+
info: {
|
|
171681
|
+
originalTokenCount,
|
|
171682
|
+
newTokenCount,
|
|
171683
|
+
compressionStatus: CompressionStatus.COMPRESSION_FAILED_INFLATED_TOKEN_COUNT
|
|
171684
|
+
}
|
|
171685
|
+
};
|
|
171686
|
+
} else {
|
|
171687
|
+
uiTelemetryService.setLastPromptTokenCount(newTokenCount);
|
|
171688
|
+
try {
|
|
171689
|
+
const permissionMode = String(config2.getApprovalMode());
|
|
171690
|
+
await config2.getHookSystem()?.fireSessionStartEvent(SessionStartSource.Compact, model ?? "", permissionMode, void 0, signal);
|
|
171691
|
+
} catch (err3) {
|
|
171692
|
+
config2.getDebugLogger().warn(`SessionStart hook failed: ${err3}`);
|
|
171693
|
+
}
|
|
171694
|
+
return {
|
|
171695
|
+
newHistory,
|
|
171696
|
+
info: {
|
|
171697
|
+
originalTokenCount,
|
|
171698
|
+
newTokenCount,
|
|
171699
|
+
compressionStatus: CompressionStatus.COMPRESSED
|
|
171700
|
+
}
|
|
171701
|
+
};
|
|
171702
|
+
}
|
|
171703
|
+
}
|
|
171704
|
+
// ---------------------------------------------------------------------------
|
|
171705
|
+
// Session Memory fast-path compaction
|
|
171706
|
+
// ---------------------------------------------------------------------------
|
|
171707
|
+
/**
|
|
171708
|
+
* Attempt to compact using the continuously-maintained session notes file
|
|
171709
|
+
* instead of making a fresh LLM summarisation call.
|
|
171710
|
+
*
|
|
171711
|
+
* Returns null when the notes are absent, empty, or would not meaningfully
|
|
171712
|
+
* reduce the context (≥ 90 % of original tokens), causing the caller to fall
|
|
171713
|
+
* through to the normal LLM compression pipeline.
|
|
171714
|
+
*/
|
|
171715
|
+
async trySessionMemoryCompaction(history, originalTokenCount, config2) {
|
|
171716
|
+
try {
|
|
171717
|
+
await waitForExtraction();
|
|
171718
|
+
const projectDir = config2.getProjectRoot();
|
|
171719
|
+
const notes = await readSessionNotes(projectDir);
|
|
171720
|
+
if (!notes || isSessionNotesEmpty(notes))
|
|
171721
|
+
return null;
|
|
171722
|
+
const { truncated, wasTruncated } = truncateNotesForCompact(notes);
|
|
171723
|
+
const summaryText = `[SESSION_MEMORY_SUMMARY]
|
|
171724
|
+
The following is a running summary of this conversation maintained by the session memory agent.
|
|
171725
|
+
` + (wasTruncated ? `(Some sections were truncated for length. Full notes at ${config2.getProjectRoot()}/.proto/session-notes.md)
|
|
171726
|
+
` : "") + `
|
|
171727
|
+
${truncated}`;
|
|
171728
|
+
const MIN_PRESERVED_TOKENS = 1e4;
|
|
171729
|
+
const lastSummarized = getLastSummarizedCursorIndex();
|
|
171730
|
+
let keepFromIndex = lastSummarized >= 0 ? lastSummarized + 1 : history.length;
|
|
171731
|
+
let preservedTokens = estimateHistoryTokens(history.slice(keepFromIndex));
|
|
171732
|
+
while (keepFromIndex > 0 && preservedTokens < MIN_PRESERVED_TOKENS) {
|
|
171733
|
+
keepFromIndex--;
|
|
171734
|
+
preservedTokens += estimateHistoryTokens([history[keepFromIndex]]);
|
|
171735
|
+
}
|
|
171736
|
+
keepFromIndex = adjustIndexForToolPairs(history, keepFromIndex);
|
|
171737
|
+
const preservedTail = history.slice(keepFromIndex);
|
|
171738
|
+
const summaryUserMsg = {
|
|
171739
|
+
role: "user",
|
|
171740
|
+
parts: [{ text: summaryText }]
|
|
171741
|
+
};
|
|
171742
|
+
const summaryAckMsg = {
|
|
171743
|
+
role: "model",
|
|
171744
|
+
parts: [
|
|
171745
|
+
{
|
|
171746
|
+
text: "Understood. I have the session summary and will continue from the current state."
|
|
171747
|
+
}
|
|
171748
|
+
]
|
|
171749
|
+
};
|
|
171750
|
+
const newHistory = [summaryUserMsg, summaryAckMsg, ...preservedTail];
|
|
171751
|
+
const newTokenCount = estimateHistoryTokens(newHistory);
|
|
171752
|
+
if (newTokenCount >= originalTokenCount * 0.9)
|
|
171753
|
+
return null;
|
|
171754
|
+
return {
|
|
171755
|
+
newHistory,
|
|
171756
|
+
info: {
|
|
171757
|
+
originalTokenCount,
|
|
171758
|
+
newTokenCount,
|
|
171759
|
+
compressionStatus: CompressionStatus.COMPRESSED
|
|
171760
|
+
}
|
|
171761
|
+
};
|
|
171762
|
+
} catch {
|
|
171763
|
+
return null;
|
|
171764
|
+
}
|
|
171765
|
+
}
|
|
171766
|
+
};
|
|
171767
|
+
__name(estimateHistoryTokens, "estimateHistoryTokens");
|
|
171768
|
+
__name(adjustIndexForToolPairs, "adjustIndexForToolPairs");
|
|
171769
|
+
}
|
|
171770
|
+
});
|
|
171771
|
+
|
|
171772
|
+
// node_modules/async-mutex/index.mjs
|
|
171773
|
+
function insertSorted(a2, v2) {
|
|
171774
|
+
const i4 = findIndexFromEnd(a2, (other2) => v2.priority <= other2.priority);
|
|
171775
|
+
a2.splice(i4 + 1, 0, v2);
|
|
171776
|
+
}
|
|
171777
|
+
function findIndexFromEnd(a2, predicate) {
|
|
171778
|
+
for (let i4 = a2.length - 1; i4 >= 0; i4--) {
|
|
171779
|
+
if (predicate(a2[i4])) {
|
|
171780
|
+
return i4;
|
|
171781
|
+
}
|
|
171782
|
+
}
|
|
171783
|
+
return -1;
|
|
171784
|
+
}
|
|
171785
|
+
var E_TIMEOUT, E_ALREADY_LOCKED, E_CANCELED, __awaiter$2, Semaphore, __awaiter$1, Mutex;
|
|
171786
|
+
var init_async_mutex = __esm({
|
|
171787
|
+
"node_modules/async-mutex/index.mjs"() {
|
|
171788
|
+
init_esbuild_shims();
|
|
171789
|
+
E_TIMEOUT = new Error("timeout while waiting for mutex to become available");
|
|
171790
|
+
E_ALREADY_LOCKED = new Error("mutex already locked");
|
|
171791
|
+
E_CANCELED = new Error("request for lock canceled");
|
|
171792
|
+
__awaiter$2 = function(thisArg, _arguments, P2, generator) {
|
|
171793
|
+
function adopt(value) {
|
|
171794
|
+
return value instanceof P2 ? value : new P2(function(resolve37) {
|
|
171795
|
+
resolve37(value);
|
|
171796
|
+
});
|
|
171797
|
+
}
|
|
171798
|
+
__name(adopt, "adopt");
|
|
171799
|
+
return new (P2 || (P2 = Promise))(function(resolve37, reject) {
|
|
171800
|
+
function fulfilled(value) {
|
|
171801
|
+
try {
|
|
171802
|
+
step(generator.next(value));
|
|
171803
|
+
} catch (e4) {
|
|
171804
|
+
reject(e4);
|
|
171805
|
+
}
|
|
171806
|
+
}
|
|
171807
|
+
__name(fulfilled, "fulfilled");
|
|
171808
|
+
function rejected(value) {
|
|
171809
|
+
try {
|
|
171810
|
+
step(generator["throw"](value));
|
|
171811
|
+
} catch (e4) {
|
|
171812
|
+
reject(e4);
|
|
171813
|
+
}
|
|
171814
|
+
}
|
|
171815
|
+
__name(rejected, "rejected");
|
|
171816
|
+
function step(result) {
|
|
171817
|
+
result.done ? resolve37(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
171818
|
+
}
|
|
171819
|
+
__name(step, "step");
|
|
171820
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
171821
|
+
});
|
|
171822
|
+
};
|
|
171823
|
+
Semaphore = class {
|
|
171824
|
+
static {
|
|
171825
|
+
__name(this, "Semaphore");
|
|
171826
|
+
}
|
|
171827
|
+
constructor(_value, _cancelError = E_CANCELED) {
|
|
171828
|
+
this._value = _value;
|
|
171829
|
+
this._cancelError = _cancelError;
|
|
171830
|
+
this._queue = [];
|
|
171831
|
+
this._weightedWaiters = [];
|
|
171832
|
+
}
|
|
171833
|
+
acquire(weight = 1, priority = 0) {
|
|
171834
|
+
if (weight <= 0)
|
|
171835
|
+
throw new Error(`invalid weight ${weight}: must be positive`);
|
|
171836
|
+
return new Promise((resolve37, reject) => {
|
|
171837
|
+
const task = { resolve: resolve37, reject, weight, priority };
|
|
171838
|
+
const i4 = findIndexFromEnd(this._queue, (other2) => priority <= other2.priority);
|
|
171839
|
+
if (i4 === -1 && weight <= this._value) {
|
|
171840
|
+
this._dispatchItem(task);
|
|
171841
|
+
} else {
|
|
171842
|
+
this._queue.splice(i4 + 1, 0, task);
|
|
171843
|
+
}
|
|
171844
|
+
});
|
|
171845
|
+
}
|
|
171846
|
+
runExclusive(callback_1) {
|
|
171847
|
+
return __awaiter$2(this, arguments, void 0, function* (callback, weight = 1, priority = 0) {
|
|
171848
|
+
const [value, release2] = yield this.acquire(weight, priority);
|
|
171849
|
+
try {
|
|
171850
|
+
return yield callback(value);
|
|
171851
|
+
} finally {
|
|
171852
|
+
release2();
|
|
171853
|
+
}
|
|
171854
|
+
});
|
|
171855
|
+
}
|
|
171856
|
+
waitForUnlock(weight = 1, priority = 0) {
|
|
171857
|
+
if (weight <= 0)
|
|
171858
|
+
throw new Error(`invalid weight ${weight}: must be positive`);
|
|
171859
|
+
if (this._couldLockImmediately(weight, priority)) {
|
|
171860
|
+
return Promise.resolve();
|
|
171861
|
+
} else {
|
|
171862
|
+
return new Promise((resolve37) => {
|
|
171863
|
+
if (!this._weightedWaiters[weight - 1])
|
|
171864
|
+
this._weightedWaiters[weight - 1] = [];
|
|
171865
|
+
insertSorted(this._weightedWaiters[weight - 1], { resolve: resolve37, priority });
|
|
171866
|
+
});
|
|
171867
|
+
}
|
|
171868
|
+
}
|
|
171869
|
+
isLocked() {
|
|
171870
|
+
return this._value <= 0;
|
|
171871
|
+
}
|
|
171872
|
+
getValue() {
|
|
171873
|
+
return this._value;
|
|
171874
|
+
}
|
|
171875
|
+
setValue(value) {
|
|
171876
|
+
this._value = value;
|
|
171877
|
+
this._dispatchQueue();
|
|
171878
|
+
}
|
|
171879
|
+
release(weight = 1) {
|
|
171880
|
+
if (weight <= 0)
|
|
171881
|
+
throw new Error(`invalid weight ${weight}: must be positive`);
|
|
171882
|
+
this._value += weight;
|
|
171883
|
+
this._dispatchQueue();
|
|
171884
|
+
}
|
|
171885
|
+
cancel() {
|
|
171886
|
+
this._queue.forEach((entry) => entry.reject(this._cancelError));
|
|
171887
|
+
this._queue = [];
|
|
171888
|
+
}
|
|
171889
|
+
_dispatchQueue() {
|
|
171890
|
+
this._drainUnlockWaiters();
|
|
171891
|
+
while (this._queue.length > 0 && this._queue[0].weight <= this._value) {
|
|
171892
|
+
this._dispatchItem(this._queue.shift());
|
|
171893
|
+
this._drainUnlockWaiters();
|
|
171894
|
+
}
|
|
171895
|
+
}
|
|
171896
|
+
_dispatchItem(item) {
|
|
171897
|
+
const previousValue = this._value;
|
|
171898
|
+
this._value -= item.weight;
|
|
171899
|
+
item.resolve([previousValue, this._newReleaser(item.weight)]);
|
|
171900
|
+
}
|
|
171901
|
+
_newReleaser(weight) {
|
|
171902
|
+
let called = false;
|
|
171903
|
+
return () => {
|
|
171904
|
+
if (called)
|
|
171905
|
+
return;
|
|
171906
|
+
called = true;
|
|
171907
|
+
this.release(weight);
|
|
171908
|
+
};
|
|
171909
|
+
}
|
|
171910
|
+
_drainUnlockWaiters() {
|
|
171911
|
+
if (this._queue.length === 0) {
|
|
171912
|
+
for (let weight = this._value; weight > 0; weight--) {
|
|
171913
|
+
const waiters = this._weightedWaiters[weight - 1];
|
|
171914
|
+
if (!waiters)
|
|
171915
|
+
continue;
|
|
171916
|
+
waiters.forEach((waiter) => waiter.resolve());
|
|
171917
|
+
this._weightedWaiters[weight - 1] = [];
|
|
171918
|
+
}
|
|
171919
|
+
} else {
|
|
171920
|
+
const queuedPriority = this._queue[0].priority;
|
|
171921
|
+
for (let weight = this._value; weight > 0; weight--) {
|
|
171922
|
+
const waiters = this._weightedWaiters[weight - 1];
|
|
171923
|
+
if (!waiters)
|
|
171924
|
+
continue;
|
|
171925
|
+
const i4 = waiters.findIndex((waiter) => waiter.priority <= queuedPriority);
|
|
171926
|
+
(i4 === -1 ? waiters : waiters.splice(0, i4)).forEach((waiter) => waiter.resolve());
|
|
171927
|
+
}
|
|
171928
|
+
}
|
|
171929
|
+
}
|
|
171930
|
+
_couldLockImmediately(weight, priority) {
|
|
171931
|
+
return (this._queue.length === 0 || this._queue[0].priority < priority) && weight <= this._value;
|
|
171932
|
+
}
|
|
171933
|
+
};
|
|
171934
|
+
__name(insertSorted, "insertSorted");
|
|
171935
|
+
__name(findIndexFromEnd, "findIndexFromEnd");
|
|
171936
|
+
__awaiter$1 = function(thisArg, _arguments, P2, generator) {
|
|
171937
|
+
function adopt(value) {
|
|
171938
|
+
return value instanceof P2 ? value : new P2(function(resolve37) {
|
|
171939
|
+
resolve37(value);
|
|
171940
|
+
});
|
|
171941
|
+
}
|
|
171942
|
+
__name(adopt, "adopt");
|
|
171943
|
+
return new (P2 || (P2 = Promise))(function(resolve37, reject) {
|
|
171944
|
+
function fulfilled(value) {
|
|
171945
|
+
try {
|
|
171946
|
+
step(generator.next(value));
|
|
171947
|
+
} catch (e4) {
|
|
171948
|
+
reject(e4);
|
|
171949
|
+
}
|
|
171950
|
+
}
|
|
171951
|
+
__name(fulfilled, "fulfilled");
|
|
171952
|
+
function rejected(value) {
|
|
171953
|
+
try {
|
|
171954
|
+
step(generator["throw"](value));
|
|
171955
|
+
} catch (e4) {
|
|
171956
|
+
reject(e4);
|
|
171957
|
+
}
|
|
171958
|
+
}
|
|
171959
|
+
__name(rejected, "rejected");
|
|
171960
|
+
function step(result) {
|
|
171961
|
+
result.done ? resolve37(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
171962
|
+
}
|
|
171963
|
+
__name(step, "step");
|
|
171964
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
171965
|
+
});
|
|
171966
|
+
};
|
|
171967
|
+
Mutex = class {
|
|
171968
|
+
static {
|
|
171969
|
+
__name(this, "Mutex");
|
|
171970
|
+
}
|
|
171971
|
+
constructor(cancelError) {
|
|
171972
|
+
this._semaphore = new Semaphore(1, cancelError);
|
|
171973
|
+
}
|
|
171974
|
+
acquire() {
|
|
171975
|
+
return __awaiter$1(this, arguments, void 0, function* (priority = 0) {
|
|
171976
|
+
const [, releaser] = yield this._semaphore.acquire(1, priority);
|
|
171977
|
+
return releaser;
|
|
171978
|
+
});
|
|
171979
|
+
}
|
|
171980
|
+
runExclusive(callback, priority = 0) {
|
|
171981
|
+
return this._semaphore.runExclusive(() => callback(), 1, priority);
|
|
171982
|
+
}
|
|
171983
|
+
isLocked() {
|
|
171984
|
+
return this._semaphore.isLocked();
|
|
171985
|
+
}
|
|
171986
|
+
waitForUnlock(priority = 0) {
|
|
171987
|
+
return this._semaphore.waitForUnlock(1, priority);
|
|
171988
|
+
}
|
|
171989
|
+
release() {
|
|
171990
|
+
if (this._semaphore.isLocked())
|
|
171991
|
+
this._semaphore.release();
|
|
171992
|
+
}
|
|
171993
|
+
cancel() {
|
|
171994
|
+
return this._semaphore.cancel();
|
|
171995
|
+
}
|
|
171996
|
+
};
|
|
171997
|
+
}
|
|
171998
|
+
});
|
|
171999
|
+
|
|
172000
|
+
// packages/core/dist/src/utils/jsonl-utils.js
|
|
172001
|
+
import fs20 from "node:fs";
|
|
172002
|
+
import path19 from "node:path";
|
|
172003
|
+
import readline from "node:readline";
|
|
172004
|
+
function getFileLock(filePath) {
|
|
172005
|
+
if (!fileLocks.has(filePath)) {
|
|
172006
|
+
fileLocks.set(filePath, new Mutex());
|
|
172007
|
+
}
|
|
172008
|
+
return fileLocks.get(filePath);
|
|
172009
|
+
}
|
|
172010
|
+
async function readLines(filePath, count) {
|
|
172011
|
+
try {
|
|
172012
|
+
const fileStream = fs20.createReadStream(filePath);
|
|
172013
|
+
const rl = readline.createInterface({
|
|
172014
|
+
input: fileStream,
|
|
172015
|
+
crlfDelay: Infinity
|
|
172016
|
+
});
|
|
172017
|
+
const results = [];
|
|
172018
|
+
for await (const line of rl) {
|
|
172019
|
+
if (results.length >= count)
|
|
172020
|
+
break;
|
|
172021
|
+
const trimmed2 = line.trim();
|
|
172022
|
+
if (trimmed2.length > 0) {
|
|
172023
|
+
results.push(JSON.parse(trimmed2));
|
|
172024
|
+
}
|
|
172025
|
+
}
|
|
172026
|
+
return results;
|
|
172027
|
+
} catch (error40) {
|
|
172028
|
+
if (error40.code !== "ENOENT") {
|
|
172029
|
+
debugLogger23.error(`Error reading first ${count} lines from ${filePath}:`, error40);
|
|
172030
|
+
}
|
|
172031
|
+
return [];
|
|
172032
|
+
}
|
|
172033
|
+
}
|
|
172034
|
+
async function read(filePath) {
|
|
172035
|
+
try {
|
|
172036
|
+
const fileStream = fs20.createReadStream(filePath);
|
|
172037
|
+
const rl = readline.createInterface({
|
|
172038
|
+
input: fileStream,
|
|
172039
|
+
crlfDelay: Infinity
|
|
172040
|
+
});
|
|
172041
|
+
const results = [];
|
|
172042
|
+
for await (const line of rl) {
|
|
172043
|
+
const trimmed2 = line.trim();
|
|
172044
|
+
if (trimmed2.length > 0) {
|
|
172045
|
+
results.push(JSON.parse(trimmed2));
|
|
172046
|
+
}
|
|
172047
|
+
}
|
|
172048
|
+
return results;
|
|
172049
|
+
} catch (error40) {
|
|
172050
|
+
if (error40.code !== "ENOENT") {
|
|
172051
|
+
debugLogger23.error(`Error reading ${filePath}:`, error40);
|
|
172052
|
+
}
|
|
172053
|
+
return [];
|
|
172054
|
+
}
|
|
172055
|
+
}
|
|
172056
|
+
async function writeLine(filePath, data) {
|
|
172057
|
+
const lock = getFileLock(filePath);
|
|
172058
|
+
await lock.runExclusive(() => {
|
|
172059
|
+
const line = `${JSON.stringify(data)}
|
|
172060
|
+
`;
|
|
172061
|
+
const dir = path19.dirname(filePath);
|
|
172062
|
+
if (!fs20.existsSync(dir)) {
|
|
172063
|
+
fs20.mkdirSync(dir, { recursive: true });
|
|
172064
|
+
}
|
|
172065
|
+
fs20.appendFileSync(filePath, line, "utf8");
|
|
172066
|
+
});
|
|
172067
|
+
}
|
|
172068
|
+
function writeLineSync(filePath, data) {
|
|
172069
|
+
const line = `${JSON.stringify(data)}
|
|
172070
|
+
`;
|
|
172071
|
+
const dir = path19.dirname(filePath);
|
|
172072
|
+
if (!fs20.existsSync(dir)) {
|
|
172073
|
+
fs20.mkdirSync(dir, { recursive: true });
|
|
172074
|
+
}
|
|
172075
|
+
fs20.appendFileSync(filePath, line, "utf8");
|
|
172076
|
+
}
|
|
172077
|
+
function write(filePath, data) {
|
|
172078
|
+
const lines = data.map((item) => JSON.stringify(item)).join("\n");
|
|
172079
|
+
const dir = path19.dirname(filePath);
|
|
172080
|
+
if (!fs20.existsSync(dir)) {
|
|
172081
|
+
fs20.mkdirSync(dir, { recursive: true });
|
|
172082
|
+
}
|
|
172083
|
+
fs20.writeFileSync(filePath, `${lines}
|
|
172084
|
+
`, "utf8");
|
|
172085
|
+
}
|
|
172086
|
+
async function countLines(filePath) {
|
|
172087
|
+
try {
|
|
172088
|
+
const fileStream = fs20.createReadStream(filePath);
|
|
172089
|
+
const rl = readline.createInterface({
|
|
172090
|
+
input: fileStream,
|
|
172091
|
+
crlfDelay: Infinity
|
|
172092
|
+
});
|
|
172093
|
+
let count = 0;
|
|
172094
|
+
for await (const line of rl) {
|
|
172095
|
+
if (line.trim().length > 0) {
|
|
172096
|
+
count++;
|
|
172097
|
+
}
|
|
172098
|
+
}
|
|
172099
|
+
return count;
|
|
172100
|
+
} catch (error40) {
|
|
172101
|
+
if (error40.code !== "ENOENT") {
|
|
172102
|
+
debugLogger23.error(`Error counting lines in ${filePath}:`, error40);
|
|
172103
|
+
}
|
|
172104
|
+
return 0;
|
|
172105
|
+
}
|
|
172106
|
+
}
|
|
172107
|
+
function exists(filePath) {
|
|
172108
|
+
try {
|
|
172109
|
+
const stats = fs20.statSync(filePath);
|
|
172110
|
+
return stats.isFile() && stats.size > 0;
|
|
172111
|
+
} catch {
|
|
172112
|
+
return false;
|
|
172113
|
+
}
|
|
172114
|
+
}
|
|
172115
|
+
var debugLogger23, fileLocks;
|
|
172116
|
+
var init_jsonl_utils = __esm({
|
|
172117
|
+
"packages/core/dist/src/utils/jsonl-utils.js"() {
|
|
172118
|
+
"use strict";
|
|
172119
|
+
init_esbuild_shims();
|
|
172120
|
+
init_async_mutex();
|
|
172121
|
+
init_debugLogger();
|
|
172122
|
+
debugLogger23 = createDebugLogger("JSONL");
|
|
172123
|
+
fileLocks = /* @__PURE__ */ new Map();
|
|
172124
|
+
__name(getFileLock, "getFileLock");
|
|
172125
|
+
__name(readLines, "readLines");
|
|
172126
|
+
__name(read, "read");
|
|
172127
|
+
__name(writeLine, "writeLine");
|
|
172128
|
+
__name(writeLineSync, "writeLineSync");
|
|
172129
|
+
__name(write, "write");
|
|
172130
|
+
__name(countLines, "countLines");
|
|
172131
|
+
__name(exists, "exists");
|
|
172132
|
+
}
|
|
172133
|
+
});
|
|
172134
|
+
|
|
172135
|
+
// packages/core/dist/src/services/chatRecordingService.js
|
|
172136
|
+
import path20 from "node:path";
|
|
172137
|
+
import fs21 from "node:fs";
|
|
172138
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
172139
|
+
var debugLogger24, ChatRecordingService;
|
|
172140
|
+
var init_chatRecordingService = __esm({
|
|
172141
|
+
"packages/core/dist/src/services/chatRecordingService.js"() {
|
|
172142
|
+
"use strict";
|
|
172143
|
+
init_esbuild_shims();
|
|
172144
|
+
init_config3();
|
|
172145
|
+
init_node();
|
|
172146
|
+
init_jsonl_utils();
|
|
172147
|
+
init_gitUtils();
|
|
172148
|
+
init_debugLogger();
|
|
172149
|
+
debugLogger24 = createDebugLogger("CHAT_RECORDING");
|
|
172150
|
+
ChatRecordingService = class {
|
|
172151
|
+
static {
|
|
172152
|
+
__name(this, "ChatRecordingService");
|
|
172153
|
+
}
|
|
172154
|
+
/** UUID of the last written record in the chain */
|
|
172155
|
+
lastRecordUuid = null;
|
|
172156
|
+
config;
|
|
172157
|
+
/** In-memory cache of the current session's custom title (for re-append on exit) */
|
|
172158
|
+
currentCustomTitle;
|
|
172159
|
+
constructor(config2) {
|
|
172160
|
+
this.config = config2;
|
|
172161
|
+
this.lastRecordUuid = config2.getResumedSessionData()?.lastCompletedUuid ?? null;
|
|
172162
|
+
if (config2.getResumedSessionData()) {
|
|
172163
|
+
try {
|
|
172164
|
+
const sessionService = config2.getSessionService();
|
|
172165
|
+
this.currentCustomTitle = sessionService.getSessionTitle(config2.getSessionId());
|
|
172166
|
+
this.finalize();
|
|
172167
|
+
} catch {
|
|
172168
|
+
}
|
|
172169
|
+
}
|
|
172170
|
+
}
|
|
172171
|
+
/**
|
|
172172
|
+
* Returns the session ID.
|
|
172173
|
+
* @returns The session ID.
|
|
172174
|
+
*/
|
|
172175
|
+
getSessionId() {
|
|
172176
|
+
return this.config.getSessionId();
|
|
172177
|
+
}
|
|
172178
|
+
/**
|
|
172179
|
+
* Ensures the chats directory exists, creating it if it doesn't exist.
|
|
172180
|
+
* @returns The path to the chats directory.
|
|
172181
|
+
* @throws Error if the directory cannot be created.
|
|
172182
|
+
*/
|
|
172183
|
+
ensureChatsDir() {
|
|
172184
|
+
const projectDir = this.config.storage.getProjectDir();
|
|
172185
|
+
const chatsDir = path20.join(projectDir, "chats");
|
|
172186
|
+
try {
|
|
172187
|
+
fs21.mkdirSync(chatsDir, { recursive: true });
|
|
172188
|
+
} catch {
|
|
172189
|
+
}
|
|
172190
|
+
return chatsDir;
|
|
172191
|
+
}
|
|
172192
|
+
/**
|
|
172193
|
+
* Ensures the conversation file exists, creating it if it doesn't exist.
|
|
172194
|
+
* Uses atomic file creation to avoid race conditions.
|
|
172195
|
+
* @returns The path to the conversation file.
|
|
172196
|
+
* @throws Error if the file cannot be created or accessed.
|
|
172197
|
+
*/
|
|
172198
|
+
ensureConversationFile() {
|
|
172199
|
+
const chatsDir = this.ensureChatsDir();
|
|
172200
|
+
const sessionId = this.getSessionId();
|
|
172201
|
+
const safeFilename = `${sessionId}.jsonl`;
|
|
172202
|
+
const conversationFile = path20.join(chatsDir, safeFilename);
|
|
172203
|
+
if (fs21.existsSync(conversationFile)) {
|
|
172204
|
+
return conversationFile;
|
|
172205
|
+
}
|
|
172206
|
+
try {
|
|
172207
|
+
fs21.writeFileSync(conversationFile, "", { flag: "wx", encoding: "utf8" });
|
|
172208
|
+
} catch (error40) {
|
|
172209
|
+
const nodeError = error40;
|
|
172210
|
+
if (nodeError.code !== "EEXIST") {
|
|
172211
|
+
const message = error40 instanceof Error ? error40.message : String(error40);
|
|
172212
|
+
throw new Error(`Failed to create conversation file at ${conversationFile}: ${message}`);
|
|
172213
|
+
}
|
|
172214
|
+
}
|
|
172215
|
+
return conversationFile;
|
|
172216
|
+
}
|
|
172217
|
+
/**
|
|
172218
|
+
* Creates base fields for a ChatRecord.
|
|
172219
|
+
*/
|
|
172220
|
+
createBaseRecord(type) {
|
|
172221
|
+
return {
|
|
172222
|
+
uuid: randomUUID2(),
|
|
172223
|
+
parentUuid: this.lastRecordUuid,
|
|
172224
|
+
sessionId: this.getSessionId(),
|
|
172225
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
172226
|
+
type,
|
|
172227
|
+
cwd: this.config.getProjectRoot(),
|
|
172228
|
+
version: this.config.getCliVersion() || "unknown",
|
|
172229
|
+
gitBranch: getGitBranch(this.config.getProjectRoot())
|
|
172230
|
+
};
|
|
172231
|
+
}
|
|
172232
|
+
/**
|
|
172233
|
+
* Appends a record to the session file and updates lastRecordUuid.
|
|
172234
|
+
*/
|
|
172235
|
+
appendRecord(record2) {
|
|
172236
|
+
try {
|
|
172237
|
+
const conversationFile = this.ensureConversationFile();
|
|
172238
|
+
writeLineSync(conversationFile, record2);
|
|
172239
|
+
this.lastRecordUuid = record2.uuid;
|
|
172240
|
+
} catch (error40) {
|
|
172241
|
+
debugLogger24.error("Error appending record:", error40);
|
|
172242
|
+
throw error40;
|
|
172243
|
+
}
|
|
172244
|
+
}
|
|
172245
|
+
/**
|
|
172246
|
+
* Records a user message.
|
|
172247
|
+
* Writes immediately to disk.
|
|
172248
|
+
*
|
|
172249
|
+
* @param message The raw PartListUnion object as used with the API
|
|
172250
|
+
*/
|
|
172251
|
+
recordUserMessage(message) {
|
|
172252
|
+
try {
|
|
172253
|
+
const record2 = {
|
|
172254
|
+
...this.createBaseRecord("user"),
|
|
172255
|
+
message: createUserContent(message)
|
|
172256
|
+
};
|
|
172257
|
+
this.appendRecord(record2);
|
|
172258
|
+
} catch (error40) {
|
|
172259
|
+
debugLogger24.error("Error saving user message:", error40);
|
|
172260
|
+
}
|
|
172261
|
+
}
|
|
172262
|
+
/**
|
|
172263
|
+
* Records an assistant turn with all available data.
|
|
172264
|
+
* Writes immediately to disk.
|
|
172265
|
+
*
|
|
172266
|
+
* @param data.message The raw PartListUnion object from the model response
|
|
172267
|
+
* @param data.model The model name
|
|
172268
|
+
* @param data.tokens Token usage statistics
|
|
172269
|
+
* @param data.contextWindowSize Context window size of the model
|
|
172270
|
+
* @param data.toolCallsMetadata Enriched tool call info for UI recovery
|
|
172271
|
+
*/
|
|
172272
|
+
recordAssistantTurn(data) {
|
|
172273
|
+
try {
|
|
172274
|
+
const record2 = {
|
|
172275
|
+
...this.createBaseRecord("assistant"),
|
|
172276
|
+
model: data.model
|
|
172277
|
+
};
|
|
172278
|
+
if (data.message !== void 0) {
|
|
172279
|
+
record2.message = createModelContent(data.message);
|
|
172280
|
+
}
|
|
172281
|
+
if (data.tokens) {
|
|
172282
|
+
record2.usageMetadata = data.tokens;
|
|
172283
|
+
}
|
|
172284
|
+
if (data.contextWindowSize !== void 0) {
|
|
172285
|
+
record2.contextWindowSize = data.contextWindowSize;
|
|
172286
|
+
}
|
|
172287
|
+
this.appendRecord(record2);
|
|
172288
|
+
} catch (error40) {
|
|
172289
|
+
debugLogger24.error("Error saving assistant turn:", error40);
|
|
172290
|
+
}
|
|
172291
|
+
}
|
|
172292
|
+
/**
|
|
172293
|
+
* Records tool results (function responses) sent back to the model.
|
|
172294
|
+
* Writes immediately to disk.
|
|
172295
|
+
*
|
|
172296
|
+
* @param message The raw PartListUnion object with functionResponse parts
|
|
172297
|
+
* @param toolCallResult Optional tool call result info for UI recovery
|
|
172298
|
+
*/
|
|
172299
|
+
recordToolResult(message, toolCallResult) {
|
|
172300
|
+
try {
|
|
172301
|
+
const record2 = {
|
|
172302
|
+
...this.createBaseRecord("tool_result"),
|
|
172303
|
+
message: createUserContent(message)
|
|
172304
|
+
};
|
|
172305
|
+
if (toolCallResult) {
|
|
172306
|
+
if (typeof toolCallResult.resultDisplay === "object" && toolCallResult.resultDisplay !== null && "type" in toolCallResult.resultDisplay && toolCallResult.resultDisplay.type === "task_execution") {
|
|
172307
|
+
const taskResult = toolCallResult.resultDisplay;
|
|
172308
|
+
record2.toolCallResult = {
|
|
172309
|
+
...toolCallResult,
|
|
172310
|
+
resultDisplay: {
|
|
172311
|
+
...taskResult,
|
|
172312
|
+
toolCalls: []
|
|
172313
|
+
}
|
|
172314
|
+
};
|
|
172315
|
+
} else {
|
|
172316
|
+
record2.toolCallResult = toolCallResult;
|
|
172317
|
+
}
|
|
172318
|
+
}
|
|
172319
|
+
this.appendRecord(record2);
|
|
172320
|
+
} catch (error40) {
|
|
172321
|
+
debugLogger24.error("Error saving tool result:", error40);
|
|
172322
|
+
}
|
|
172323
|
+
}
|
|
172324
|
+
/**
|
|
172325
|
+
* Records a slash command invocation as a system record. This keeps the model
|
|
172326
|
+
* history clean while allowing resume to replay UI output for commands like
|
|
172327
|
+
* /about.
|
|
172328
|
+
*/
|
|
172329
|
+
recordSlashCommand(payload) {
|
|
172330
|
+
try {
|
|
172331
|
+
const record2 = {
|
|
172332
|
+
...this.createBaseRecord("system"),
|
|
172333
|
+
type: "system",
|
|
172334
|
+
subtype: "slash_command",
|
|
172335
|
+
systemPayload: payload
|
|
172336
|
+
};
|
|
172337
|
+
this.appendRecord(record2);
|
|
172338
|
+
} catch (error40) {
|
|
172339
|
+
debugLogger24.error("Error saving slash command record:", error40);
|
|
172340
|
+
}
|
|
172341
|
+
}
|
|
172342
|
+
/**
|
|
172343
|
+
* Records a chat compression checkpoint as a system record. This keeps the UI
|
|
172344
|
+
* history immutable while allowing resume/continue flows to reconstruct the
|
|
172345
|
+
* compressed model-facing history from the stored snapshot.
|
|
172346
|
+
*/
|
|
172347
|
+
recordChatCompression(payload) {
|
|
172348
|
+
try {
|
|
172349
|
+
const record2 = {
|
|
172350
|
+
...this.createBaseRecord("system"),
|
|
172351
|
+
type: "system",
|
|
172352
|
+
subtype: "chat_compression",
|
|
172353
|
+
systemPayload: payload
|
|
172354
|
+
};
|
|
172355
|
+
this.appendRecord(record2);
|
|
172356
|
+
} catch (error40) {
|
|
172357
|
+
debugLogger24.error("Error saving chat compression record:", error40);
|
|
172358
|
+
}
|
|
172359
|
+
}
|
|
172360
|
+
/**
|
|
172361
|
+
* Records a UI telemetry event for replaying metrics on resume.
|
|
172362
|
+
*/
|
|
172363
|
+
recordUiTelemetryEvent(uiEvent) {
|
|
172364
|
+
try {
|
|
172365
|
+
const record2 = {
|
|
172366
|
+
...this.createBaseRecord("system"),
|
|
172367
|
+
type: "system",
|
|
172368
|
+
subtype: "ui_telemetry",
|
|
172369
|
+
systemPayload: { uiEvent }
|
|
172370
|
+
};
|
|
172371
|
+
this.appendRecord(record2);
|
|
172372
|
+
} catch (error40) {
|
|
172373
|
+
debugLogger24.error("Error saving ui telemetry record:", error40);
|
|
172374
|
+
}
|
|
172375
|
+
}
|
|
172376
|
+
/**
|
|
172377
|
+
* Records a custom title for the session (set via /rename).
|
|
172378
|
+
* Appended as a system record so it persists with the session data.
|
|
172379
|
+
* Also caches the title in memory for re-append on shutdown.
|
|
172380
|
+
*
|
|
172381
|
+
* @returns true if the record was written successfully, false on I/O error.
|
|
172382
|
+
*/
|
|
172383
|
+
recordCustomTitle(customTitle) {
|
|
172384
|
+
try {
|
|
172385
|
+
const record2 = {
|
|
172386
|
+
...this.createBaseRecord("system"),
|
|
172387
|
+
type: "system",
|
|
172388
|
+
subtype: "custom_title",
|
|
172389
|
+
systemPayload: { customTitle }
|
|
172390
|
+
};
|
|
172391
|
+
this.appendRecord(record2);
|
|
172392
|
+
this.currentCustomTitle = customTitle;
|
|
172393
|
+
return true;
|
|
172394
|
+
} catch (error40) {
|
|
172395
|
+
debugLogger24.error("Error saving custom title record:", error40);
|
|
172396
|
+
return false;
|
|
172397
|
+
}
|
|
172398
|
+
}
|
|
172399
|
+
/**
|
|
172400
|
+
* Finalizes the current session by re-appending cached metadata to EOF.
|
|
172401
|
+
*
|
|
172402
|
+
* Call this whenever leaving the current session — whether switching to
|
|
172403
|
+
* another session, shutting down the process, or any other transition.
|
|
172404
|
+
* This single entry point replaces scattered re-append calls and ensures
|
|
172405
|
+
* the custom_title record stays within the last 64KB tail window that
|
|
172406
|
+
* readSessionTitleFromFile() scans.
|
|
172407
|
+
*
|
|
172408
|
+
* Best-effort: errors are logged but never thrown.
|
|
172409
|
+
*/
|
|
172410
|
+
finalize() {
|
|
172411
|
+
if (!this.currentCustomTitle) {
|
|
172412
|
+
return;
|
|
172413
|
+
}
|
|
172414
|
+
try {
|
|
172415
|
+
const record2 = {
|
|
172416
|
+
...this.createBaseRecord("system"),
|
|
172417
|
+
type: "system",
|
|
172418
|
+
subtype: "custom_title",
|
|
172419
|
+
systemPayload: { customTitle: this.currentCustomTitle }
|
|
172420
|
+
};
|
|
172421
|
+
this.appendRecord(record2);
|
|
172422
|
+
} catch (error40) {
|
|
172423
|
+
debugLogger24.error("Error finalizing session metadata:", error40);
|
|
172424
|
+
}
|
|
172425
|
+
}
|
|
172426
|
+
/**
|
|
172427
|
+
* Records @-command metadata as a system record for UI reconstruction.
|
|
172428
|
+
*/
|
|
172429
|
+
recordAtCommand(payload) {
|
|
172430
|
+
try {
|
|
172431
|
+
const record2 = {
|
|
172432
|
+
...this.createBaseRecord("system"),
|
|
172433
|
+
type: "system",
|
|
172434
|
+
subtype: "at_command",
|
|
172435
|
+
systemPayload: payload
|
|
172436
|
+
};
|
|
172437
|
+
this.appendRecord(record2);
|
|
172438
|
+
} catch (error40) {
|
|
172439
|
+
debugLogger24.error("Error saving @-command record:", error40);
|
|
172440
|
+
}
|
|
172441
|
+
}
|
|
172442
|
+
};
|
|
172449
172443
|
}
|
|
172450
172444
|
});
|
|
172451
172445
|
|
|
172452
|
-
// packages/core/dist/src/
|
|
172453
|
-
function
|
|
172454
|
-
if (
|
|
172455
|
-
return
|
|
172456
|
-
let pairsKept = 0;
|
|
172457
|
-
let cutIndex = history.length;
|
|
172458
|
-
for (let i4 = history.length - 1; i4 >= 0; i4--) {
|
|
172459
|
-
const msg = history[i4];
|
|
172460
|
-
if (msg?.role === "user" && msg.parts?.some((p2) => p2.functionResponse)) {
|
|
172461
|
-
pairsKept++;
|
|
172462
|
-
if (pairsKept >= verbatimWindowSize) {
|
|
172463
|
-
cutIndex = i4;
|
|
172464
|
-
break;
|
|
172465
|
-
}
|
|
172466
|
-
}
|
|
172446
|
+
// packages/core/dist/src/core/geminiChat.js
|
|
172447
|
+
function isValidResponse2(response) {
|
|
172448
|
+
if (response.usageMetadata) {
|
|
172449
|
+
return true;
|
|
172467
172450
|
}
|
|
172468
|
-
if (
|
|
172469
|
-
return
|
|
172470
|
-
const maskedCount = history.slice(0, cutIndex).filter((m3) => m3.role === "user" && m3.parts?.some((p2) => p2.functionResponse) || m3.role === "model" && m3.parts?.some((p2) => p2.functionCall)).length;
|
|
172471
|
-
const placeholder = {
|
|
172472
|
-
role: "user",
|
|
172473
|
-
parts: [
|
|
172474
|
-
{
|
|
172475
|
-
text: `[OBSERVATION_MASK: ${maskedCount} tool call/result pairs from earlier in the session have been masked to reduce context. The most recent ${verbatimWindowSize} pairs are preserved verbatim below.]`
|
|
172476
|
-
}
|
|
172477
|
-
]
|
|
172478
|
-
};
|
|
172479
|
-
return [placeholder, ...history.slice(cutIndex)];
|
|
172480
|
-
}
|
|
172481
|
-
function extractContentText(content) {
|
|
172482
|
-
if (!content.parts || content.parts.length === 0) {
|
|
172483
|
-
return null;
|
|
172451
|
+
if (response.candidates === void 0 || response.candidates.length === 0) {
|
|
172452
|
+
return false;
|
|
172484
172453
|
}
|
|
172485
|
-
|
|
172486
|
-
|
|
172487
|
-
return null;
|
|
172454
|
+
if (response.candidates.some((candidate) => candidate.finishReason)) {
|
|
172455
|
+
return true;
|
|
172488
172456
|
}
|
|
172489
|
-
|
|
172457
|
+
const content = response.candidates[0]?.content;
|
|
172458
|
+
return content !== void 0 && isValidContent2(content);
|
|
172490
172459
|
}
|
|
172491
|
-
function
|
|
172492
|
-
|
|
172493
|
-
|
|
172460
|
+
function isValidNonThoughtTextPart(part) {
|
|
172461
|
+
return typeof part.text === "string" && !part.thought && !part.thoughtSignature && // Technically, the model should never generate parts that have text and
|
|
172462
|
+
// any of these but we don't trust them so check anyways.
|
|
172463
|
+
!part.functionCall && !part.functionResponse && !part.inlineData && !part.fileData;
|
|
172494
172464
|
}
|
|
172495
|
-
function
|
|
172496
|
-
if (
|
|
172497
|
-
|
|
172465
|
+
function isValidContent2(content) {
|
|
172466
|
+
if (content.parts === void 0 || content.parts.length === 0) {
|
|
172467
|
+
return false;
|
|
172498
172468
|
}
|
|
172499
|
-
const
|
|
172500
|
-
|
|
172501
|
-
|
|
172502
|
-
|
|
172503
|
-
|
|
172504
|
-
|
|
172505
|
-
const content = contents[i4];
|
|
172506
|
-
if (content.role === "user" && !content.parts?.some((part) => !!part.functionResponse)) {
|
|
172507
|
-
if (cumulativeCharCount >= targetCharCount) {
|
|
172508
|
-
return i4;
|
|
172509
|
-
}
|
|
172510
|
-
lastSplitPoint = i4;
|
|
172469
|
+
for (const part of content.parts) {
|
|
172470
|
+
if (part === void 0 || Object.keys(part).length === 0) {
|
|
172471
|
+
return false;
|
|
172472
|
+
}
|
|
172473
|
+
if (!isValidContentPart(part)) {
|
|
172474
|
+
return false;
|
|
172511
172475
|
}
|
|
172512
|
-
cumulativeCharCount += charCounts[i4];
|
|
172513
172476
|
}
|
|
172514
|
-
|
|
172515
|
-
|
|
172516
|
-
|
|
172477
|
+
return true;
|
|
172478
|
+
}
|
|
172479
|
+
function isValidContentPart(part) {
|
|
172480
|
+
const isInvalid = !part.thought && !part.thoughtSignature && part.text !== void 0 && part.text === "" && part.functionCall === void 0;
|
|
172481
|
+
return !isInvalid;
|
|
172482
|
+
}
|
|
172483
|
+
function validateHistory2(history) {
|
|
172484
|
+
for (const content of history) {
|
|
172485
|
+
if (content.role !== "user" && content.role !== "model") {
|
|
172486
|
+
throw new Error(`Role must be user or model, but got ${content.role}.`);
|
|
172487
|
+
}
|
|
172517
172488
|
}
|
|
172518
|
-
|
|
172519
|
-
|
|
172489
|
+
}
|
|
172490
|
+
function extractCuratedHistory2(comprehensiveHistory) {
|
|
172491
|
+
if (comprehensiveHistory === void 0 || comprehensiveHistory.length === 0) {
|
|
172492
|
+
return [];
|
|
172520
172493
|
}
|
|
172521
|
-
|
|
172494
|
+
const curatedHistory = [];
|
|
172495
|
+
const length = comprehensiveHistory.length;
|
|
172496
|
+
let i4 = 0;
|
|
172497
|
+
while (i4 < length) {
|
|
172498
|
+
if (comprehensiveHistory[i4].role === "user") {
|
|
172499
|
+
curatedHistory.push(comprehensiveHistory[i4]);
|
|
172500
|
+
i4++;
|
|
172501
|
+
} else {
|
|
172502
|
+
const modelOutput = [];
|
|
172503
|
+
let isValid2 = true;
|
|
172504
|
+
while (i4 < length && comprehensiveHistory[i4].role === "model") {
|
|
172505
|
+
modelOutput.push(comprehensiveHistory[i4]);
|
|
172506
|
+
if (isValid2 && !isValidContent2(comprehensiveHistory[i4])) {
|
|
172507
|
+
isValid2 = false;
|
|
172508
|
+
}
|
|
172509
|
+
i4++;
|
|
172510
|
+
}
|
|
172511
|
+
if (isValid2) {
|
|
172512
|
+
curatedHistory.push(...modelOutput);
|
|
172513
|
+
}
|
|
172514
|
+
}
|
|
172515
|
+
}
|
|
172516
|
+
return curatedHistory;
|
|
172522
172517
|
}
|
|
172523
|
-
function
|
|
172524
|
-
|
|
172518
|
+
function hasTruncationCascade(contents) {
|
|
172519
|
+
if (contents.length === 0)
|
|
172520
|
+
return false;
|
|
172521
|
+
const last2 = contents[contents.length - 1];
|
|
172522
|
+
if (last2.role !== "user")
|
|
172523
|
+
return false;
|
|
172524
|
+
return last2.parts?.some((p2) => {
|
|
172525
|
+
const err3 = p2.functionResponse?.response?.["error"];
|
|
172526
|
+
return typeof err3 === "string" && err3.includes(TRUNCATION_CASCADE_MARKER);
|
|
172527
|
+
}) ?? false;
|
|
172525
172528
|
}
|
|
172526
|
-
function
|
|
172527
|
-
|
|
172528
|
-
|
|
172529
|
-
|
|
172530
|
-
|
|
172529
|
+
function trimLargeToolResponsesFromContext(contents) {
|
|
172530
|
+
return contents.map((content) => {
|
|
172531
|
+
if (content.role !== "user" || !content.parts)
|
|
172532
|
+
return content;
|
|
172533
|
+
const needsTrim = content.parts.some((p2) => {
|
|
172534
|
+
const out2 = p2.functionResponse?.response?.["output"];
|
|
172535
|
+
return typeof out2 === "string" && out2.length > LARGE_TOOL_RESPONSE_TRIM_CHARS;
|
|
172536
|
+
});
|
|
172537
|
+
if (!needsTrim)
|
|
172538
|
+
return content;
|
|
172539
|
+
return {
|
|
172540
|
+
...content,
|
|
172541
|
+
parts: content.parts.map((p2) => {
|
|
172542
|
+
const out2 = p2.functionResponse?.response?.["output"];
|
|
172543
|
+
if (typeof out2 !== "string" || out2.length <= LARGE_TOOL_RESPONSE_TRIM_CHARS)
|
|
172544
|
+
return p2;
|
|
172545
|
+
const trimmed2 = out2.slice(0, LARGE_TOOL_RESPONSE_TRIM_CHARS) + `
|
|
172546
|
+
|
|
172547
|
+
[... output trimmed from ${out2.length} to ${LARGE_TOOL_RESPONSE_TRIM_CHARS} chars to reduce context size ...]`;
|
|
172548
|
+
return {
|
|
172549
|
+
...p2,
|
|
172550
|
+
functionResponse: {
|
|
172551
|
+
...p2.functionResponse,
|
|
172552
|
+
response: {
|
|
172553
|
+
...p2.functionResponse.response,
|
|
172554
|
+
output: trimmed2
|
|
172555
|
+
}
|
|
172556
|
+
}
|
|
172557
|
+
};
|
|
172558
|
+
})
|
|
172559
|
+
};
|
|
172560
|
+
});
|
|
172561
|
+
}
|
|
172562
|
+
function trimToolErrorsFromContext(contents, maxTrimPairs = 6) {
|
|
172563
|
+
const trimmed2 = [...contents];
|
|
172564
|
+
let trimmed_count = 0;
|
|
172565
|
+
while (trimmed2.length >= 2 && trimmed_count < maxTrimPairs) {
|
|
172566
|
+
const last2 = trimmed2[trimmed2.length - 1];
|
|
172567
|
+
const prev = trimmed2[trimmed2.length - 2];
|
|
172568
|
+
if (last2.role !== "user")
|
|
172531
172569
|
break;
|
|
172532
|
-
const
|
|
172533
|
-
|
|
172534
|
-
if (isUserWithNoResponse || isModelWithNoCall)
|
|
172570
|
+
const allErrors = last2.parts?.every((p2) => p2.functionResponse !== void 0 && typeof p2.functionResponse.response?.["error"] === "string");
|
|
172571
|
+
if (!allErrors)
|
|
172535
172572
|
break;
|
|
172536
|
-
|
|
172573
|
+
if (prev.role !== "model")
|
|
172574
|
+
break;
|
|
172575
|
+
const hasToolCall2 = prev.parts?.some((p2) => p2.functionCall !== void 0);
|
|
172576
|
+
if (!hasToolCall2)
|
|
172577
|
+
break;
|
|
172578
|
+
trimmed2.splice(trimmed2.length - 2, 2);
|
|
172579
|
+
trimmed_count++;
|
|
172537
172580
|
}
|
|
172538
|
-
return
|
|
172581
|
+
return trimmed2;
|
|
172539
172582
|
}
|
|
172540
|
-
|
|
172541
|
-
|
|
172542
|
-
|
|
172583
|
+
function isSchemaDepthError(errorMessage) {
|
|
172584
|
+
return errorMessage.includes("maximum schema depth exceeded");
|
|
172585
|
+
}
|
|
172586
|
+
function isInvalidArgumentError(errorMessage) {
|
|
172587
|
+
return errorMessage.includes("Request contains an invalid argument");
|
|
172588
|
+
}
|
|
172589
|
+
var debugLogger25, StreamEventType, INVALID_CONTENT_RETRY_OPTIONS, INVALID_STREAM_RETRY_CONFIG, RATE_LIMIT_RETRY_OPTIONS, TRUNCATION_CASCADE_MARKER, LARGE_TOOL_RESPONSE_TRIM_CHARS, InvalidStreamError, GeminiChat;
|
|
172590
|
+
var init_geminiChat = __esm({
|
|
172591
|
+
"packages/core/dist/src/core/geminiChat.js"() {
|
|
172543
172592
|
"use strict";
|
|
172544
172593
|
init_esbuild_shims();
|
|
172594
|
+
init_node();
|
|
172595
|
+
init_retry();
|
|
172596
|
+
init_errors();
|
|
172597
|
+
init_debugLogger();
|
|
172598
|
+
init_errorParsing();
|
|
172599
|
+
init_rateLimit();
|
|
172600
|
+
init_contextLengthError();
|
|
172601
|
+
init_tools();
|
|
172602
|
+
init_chatCompressionService();
|
|
172545
172603
|
init_turn();
|
|
172546
|
-
init_uiTelemetry();
|
|
172547
|
-
init_tokenLimits();
|
|
172548
|
-
init_prompts();
|
|
172549
|
-
init_partUtils();
|
|
172550
172604
|
init_loggers();
|
|
172605
|
+
init_chatRecordingService();
|
|
172551
172606
|
init_types4();
|
|
172552
|
-
|
|
172553
|
-
|
|
172554
|
-
|
|
172555
|
-
|
|
172556
|
-
|
|
172557
|
-
|
|
172558
|
-
|
|
172559
|
-
|
|
172560
|
-
|
|
172561
|
-
|
|
172562
|
-
|
|
172563
|
-
|
|
172564
|
-
|
|
172565
|
-
|
|
172566
|
-
|
|
172567
|
-
|
|
172607
|
+
debugLogger25 = createDebugLogger("QWEN_CODE_CHAT");
|
|
172608
|
+
(function(StreamEventType2) {
|
|
172609
|
+
StreamEventType2["CHUNK"] = "chunk";
|
|
172610
|
+
StreamEventType2["RETRY"] = "retry";
|
|
172611
|
+
})(StreamEventType || (StreamEventType = {}));
|
|
172612
|
+
INVALID_CONTENT_RETRY_OPTIONS = {
|
|
172613
|
+
maxAttempts: 2,
|
|
172614
|
+
// 1 initial call + 1 retry
|
|
172615
|
+
initialDelayMs: 500
|
|
172616
|
+
};
|
|
172617
|
+
INVALID_STREAM_RETRY_CONFIG = {
|
|
172618
|
+
maxRetries: 2,
|
|
172619
|
+
initialDelayMs: 2e3
|
|
172620
|
+
};
|
|
172621
|
+
RATE_LIMIT_RETRY_OPTIONS = {
|
|
172622
|
+
maxRetries: 10,
|
|
172623
|
+
delayMs: 6e4
|
|
172624
|
+
};
|
|
172625
|
+
__name(isValidResponse2, "isValidResponse");
|
|
172626
|
+
__name(isValidNonThoughtTextPart, "isValidNonThoughtTextPart");
|
|
172627
|
+
__name(isValidContent2, "isValidContent");
|
|
172628
|
+
__name(isValidContentPart, "isValidContentPart");
|
|
172629
|
+
__name(validateHistory2, "validateHistory");
|
|
172630
|
+
__name(extractCuratedHistory2, "extractCuratedHistory");
|
|
172631
|
+
TRUNCATION_CASCADE_MARKER = "truncated due to max_tokens limit";
|
|
172632
|
+
LARGE_TOOL_RESPONSE_TRIM_CHARS = 1e4;
|
|
172633
|
+
__name(hasTruncationCascade, "hasTruncationCascade");
|
|
172634
|
+
__name(trimLargeToolResponsesFromContext, "trimLargeToolResponsesFromContext");
|
|
172635
|
+
__name(trimToolErrorsFromContext, "trimToolErrorsFromContext");
|
|
172636
|
+
InvalidStreamError = class extends Error {
|
|
172568
172637
|
static {
|
|
172569
|
-
__name(this, "
|
|
172638
|
+
__name(this, "InvalidStreamError");
|
|
172570
172639
|
}
|
|
172571
|
-
|
|
172572
|
-
|
|
172573
|
-
|
|
172574
|
-
|
|
172575
|
-
|
|
172576
|
-
|
|
172577
|
-
|
|
172578
|
-
|
|
172579
|
-
|
|
172580
|
-
|
|
172581
|
-
}
|
|
172582
|
-
};
|
|
172583
|
-
}
|
|
172584
|
-
const originalTokenCount = uiTelemetryService.getLastPromptTokenCount();
|
|
172585
|
-
if (!force) {
|
|
172586
|
-
const contextLimit = config2.getContentGeneratorConfig()?.contextWindowSize ?? DEFAULT_TOKEN_LIMIT;
|
|
172587
|
-
if (originalTokenCount < threshold * contextLimit) {
|
|
172588
|
-
return {
|
|
172589
|
-
newHistory: null,
|
|
172590
|
-
info: {
|
|
172591
|
-
originalTokenCount,
|
|
172592
|
-
newTokenCount: originalTokenCount,
|
|
172593
|
-
compressionStatus: CompressionStatus.NOOP
|
|
172594
|
-
}
|
|
172595
|
-
};
|
|
172596
|
-
}
|
|
172597
|
-
}
|
|
172598
|
-
if (!force) {
|
|
172599
|
-
const smResult = await this.trySessionMemoryCompaction(curatedHistory, originalTokenCount, config2);
|
|
172600
|
-
if (smResult)
|
|
172601
|
-
return smResult;
|
|
172602
|
-
}
|
|
172603
|
-
if (!force) {
|
|
172604
|
-
const saving = estimateMicrocompactSaving(curatedHistory);
|
|
172605
|
-
if (saving >= 0.2) {
|
|
172606
|
-
const { newHistory: microHistory } = applyMicrocompact(curatedHistory);
|
|
172607
|
-
const newTokenCount = Math.round(originalTokenCount * (1 - saving));
|
|
172608
|
-
uiTelemetryService.setLastPromptTokenCount(newTokenCount);
|
|
172609
|
-
return {
|
|
172610
|
-
newHistory: microHistory,
|
|
172611
|
-
info: {
|
|
172612
|
-
originalTokenCount,
|
|
172613
|
-
newTokenCount,
|
|
172614
|
-
compressionStatus: CompressionStatus.COMPRESSED
|
|
172615
|
-
}
|
|
172616
|
-
};
|
|
172617
|
-
}
|
|
172618
|
-
}
|
|
172619
|
-
const hookSystem = config2.getHookSystem();
|
|
172620
|
-
if (hookSystem) {
|
|
172621
|
-
const trigger = force ? PreCompactTrigger.Manual : PreCompactTrigger.Auto;
|
|
172622
|
-
try {
|
|
172623
|
-
await hookSystem.firePreCompactEvent(trigger, "", signal);
|
|
172624
|
-
} catch (err3) {
|
|
172625
|
-
config2.getDebugLogger().warn(`PreCompact hook failed: ${err3}`);
|
|
172626
|
-
}
|
|
172627
|
-
}
|
|
172628
|
-
const incrementalResult = await this.compressIncremental(curatedHistory, model, config2, promptId, signal);
|
|
172629
|
-
if (incrementalResult.compressed) {
|
|
172630
|
-
return this.finalizeCompression(incrementalResult.newHistory, originalTokenCount, incrementalResult.compressionInputTokenCount, incrementalResult.compressionOutputTokenCount, model, config2, signal);
|
|
172631
|
-
}
|
|
172632
|
-
return this.compressFull(curatedHistory, originalTokenCount, model, config2, promptId, force, signal);
|
|
172640
|
+
type;
|
|
172641
|
+
constructor(message, type) {
|
|
172642
|
+
super(message);
|
|
172643
|
+
this.name = "InvalidStreamError";
|
|
172644
|
+
this.type = type;
|
|
172645
|
+
}
|
|
172646
|
+
};
|
|
172647
|
+
GeminiChat = class {
|
|
172648
|
+
static {
|
|
172649
|
+
__name(this, "GeminiChat");
|
|
172633
172650
|
}
|
|
172651
|
+
config;
|
|
172652
|
+
generationConfig;
|
|
172653
|
+
history;
|
|
172654
|
+
chatRecordingService;
|
|
172655
|
+
telemetryService;
|
|
172656
|
+
// A promise to represent the current state of the message being sent to the
|
|
172657
|
+
// model.
|
|
172658
|
+
sendPromise = Promise.resolve();
|
|
172634
172659
|
/**
|
|
172635
|
-
*
|
|
172636
|
-
*
|
|
172637
|
-
*
|
|
172660
|
+
* Creates a new GeminiChat instance.
|
|
172661
|
+
*
|
|
172662
|
+
* @param config - The configuration object.
|
|
172663
|
+
* @param generationConfig - Optional generation configuration.
|
|
172664
|
+
* @param history - Optional initial conversation history.
|
|
172665
|
+
* @param chatRecordingService - Optional recording service. If provided, chat
|
|
172666
|
+
* messages will be recorded.
|
|
172667
|
+
* @param telemetryService - Optional UI telemetry service. When provided,
|
|
172668
|
+
* prompt token counts are reported on each API response. Pass `undefined`
|
|
172669
|
+
* for sub-agent chats to avoid overwriting the main agent's context usage.
|
|
172638
172670
|
*/
|
|
172639
|
-
|
|
172640
|
-
|
|
172641
|
-
|
|
172642
|
-
|
|
172643
|
-
|
|
172644
|
-
|
|
172645
|
-
|
|
172646
|
-
|
|
172647
|
-
|
|
172648
|
-
|
|
172649
|
-
|
|
172650
|
-
|
|
172651
|
-
|
|
172652
|
-
|
|
172653
|
-
|
|
172654
|
-
|
|
172655
|
-
|
|
172671
|
+
constructor(config2, generationConfig = {}, history = [], chatRecordingService, telemetryService) {
|
|
172672
|
+
this.config = config2;
|
|
172673
|
+
this.generationConfig = generationConfig;
|
|
172674
|
+
this.history = history;
|
|
172675
|
+
this.chatRecordingService = chatRecordingService;
|
|
172676
|
+
this.telemetryService = telemetryService;
|
|
172677
|
+
validateHistory2(history);
|
|
172678
|
+
}
|
|
172679
|
+
setSystemInstruction(sysInstr) {
|
|
172680
|
+
this.generationConfig.systemInstruction = sysInstr;
|
|
172681
|
+
}
|
|
172682
|
+
/**
|
|
172683
|
+
* Sends a message to the model and returns the response in chunks.
|
|
172684
|
+
*
|
|
172685
|
+
* @remarks
|
|
172686
|
+
* This method will wait for the previous message to be processed before
|
|
172687
|
+
* sending the next message.
|
|
172688
|
+
*
|
|
172689
|
+
* @see {@link Chat#sendMessage} for non-streaming method.
|
|
172690
|
+
* @param params - parameters for sending the message.
|
|
172691
|
+
* @return The model's response.
|
|
172692
|
+
*
|
|
172693
|
+
* @example
|
|
172694
|
+
* ```ts
|
|
172695
|
+
* const chat = ai.chats.create({model: 'gemini-2.0-flash'});
|
|
172696
|
+
* const response = await chat.sendMessageStream({
|
|
172697
|
+
* message: 'Why is the sky blue?'
|
|
172698
|
+
* });
|
|
172699
|
+
* for await (const chunk of response) {
|
|
172700
|
+
* console.log(chunk.text);
|
|
172701
|
+
* }
|
|
172702
|
+
* ```
|
|
172703
|
+
*/
|
|
172704
|
+
async sendMessageStream(model, params, prompt_id) {
|
|
172705
|
+
await this.sendPromise;
|
|
172706
|
+
let streamDoneResolver;
|
|
172707
|
+
const streamDonePromise = new Promise((resolve37) => {
|
|
172708
|
+
streamDoneResolver = resolve37;
|
|
172709
|
+
});
|
|
172710
|
+
this.sendPromise = streamDonePromise;
|
|
172711
|
+
const userContent = createUserContent(params.message);
|
|
172712
|
+
this.history.push(userContent);
|
|
172713
|
+
let requestContents = this.getHistory(true);
|
|
172714
|
+
if (hasTruncationCascade(requestContents)) {
|
|
172715
|
+
const withoutErrors = trimToolErrorsFromContext(requestContents);
|
|
172716
|
+
requestContents = trimLargeToolResponsesFromContext(withoutErrors);
|
|
172717
|
+
debugLogger25.warn(`MAX_TOKENS cascade detected: trimmed context from ${this.getHistory(true).length} to ${requestContents.length} entries and capped large tool responses.`);
|
|
172656
172718
|
}
|
|
172657
|
-
const
|
|
172658
|
-
|
|
172659
|
-
|
|
172660
|
-
|
|
172661
|
-
|
|
172662
|
-
|
|
172663
|
-
|
|
172664
|
-
|
|
172665
|
-
|
|
172666
|
-
|
|
172667
|
-
|
|
172719
|
+
const self2 = this;
|
|
172720
|
+
return async function* () {
|
|
172721
|
+
try {
|
|
172722
|
+
let lastError = new Error("Request failed after all retries.");
|
|
172723
|
+
let rateLimitRetryCount = 0;
|
|
172724
|
+
let invalidStreamRetryCount = 0;
|
|
172725
|
+
let reactiveCompressionAttempted = false;
|
|
172726
|
+
const cgConfig = self2.config.getContentGeneratorConfig();
|
|
172727
|
+
const maxRateLimitRetries = cgConfig?.maxRetries ?? RATE_LIMIT_RETRY_OPTIONS.maxRetries;
|
|
172728
|
+
const extraRetryErrorCodes = cgConfig?.retryErrorCodes;
|
|
172729
|
+
for (let attempt = 0; attempt < INVALID_CONTENT_RETRY_OPTIONS.maxAttempts; attempt++) {
|
|
172730
|
+
try {
|
|
172731
|
+
if (attempt > 0 || rateLimitRetryCount > 0 || invalidStreamRetryCount > 0) {
|
|
172732
|
+
yield { type: StreamEventType.RETRY };
|
|
172668
172733
|
}
|
|
172669
|
-
|
|
172734
|
+
const stream2 = await self2.makeApiCallAndProcessStream(model, requestContents, params, prompt_id);
|
|
172735
|
+
for await (const chunk of stream2) {
|
|
172736
|
+
yield { type: StreamEventType.CHUNK, value: chunk };
|
|
172737
|
+
}
|
|
172738
|
+
lastError = null;
|
|
172739
|
+
break;
|
|
172740
|
+
} catch (error40) {
|
|
172741
|
+
lastError = error40;
|
|
172742
|
+
const isRateLimit = isRateLimitError(error40, extraRetryErrorCodes);
|
|
172743
|
+
if (isRateLimit && rateLimitRetryCount < maxRateLimitRetries) {
|
|
172744
|
+
rateLimitRetryCount++;
|
|
172745
|
+
const delayMs = RATE_LIMIT_RETRY_OPTIONS.delayMs;
|
|
172746
|
+
const message = parseAndFormatApiError(error40 instanceof Error ? error40.message : String(error40));
|
|
172747
|
+
debugLogger25.warn(`Rate limit throttling detected (retry ${rateLimitRetryCount}/${maxRateLimitRetries}). Waiting ${delayMs / 1e3}s before retrying...`);
|
|
172748
|
+
yield {
|
|
172749
|
+
type: StreamEventType.RETRY,
|
|
172750
|
+
retryInfo: {
|
|
172751
|
+
message,
|
|
172752
|
+
attempt: rateLimitRetryCount,
|
|
172753
|
+
maxRetries: maxRateLimitRetries,
|
|
172754
|
+
delayMs
|
|
172755
|
+
}
|
|
172756
|
+
};
|
|
172757
|
+
attempt--;
|
|
172758
|
+
await new Promise((res) => setTimeout(res, delayMs));
|
|
172759
|
+
continue;
|
|
172760
|
+
}
|
|
172761
|
+
const isTransientStreamError = error40 instanceof InvalidStreamError;
|
|
172762
|
+
if (isTransientStreamError && invalidStreamRetryCount < INVALID_STREAM_RETRY_CONFIG.maxRetries) {
|
|
172763
|
+
invalidStreamRetryCount++;
|
|
172764
|
+
const delayMs = INVALID_STREAM_RETRY_CONFIG.initialDelayMs * invalidStreamRetryCount;
|
|
172765
|
+
debugLogger25.warn(`Invalid stream [${error40.type}] (retry ${invalidStreamRetryCount}/${INVALID_STREAM_RETRY_CONFIG.maxRetries}). Waiting ${delayMs / 1e3}s before retrying...`);
|
|
172766
|
+
logContentRetry(self2.config, new ContentRetryEvent(invalidStreamRetryCount - 1, error40.type, delayMs, model));
|
|
172767
|
+
yield { type: StreamEventType.RETRY };
|
|
172768
|
+
attempt--;
|
|
172769
|
+
await new Promise((res) => setTimeout(res, delayMs));
|
|
172770
|
+
continue;
|
|
172771
|
+
}
|
|
172772
|
+
if (isTransientStreamError && error40.type === "NO_RESPONSE_TEXT") {
|
|
172773
|
+
const trimmedContents = trimToolErrorsFromContext(requestContents);
|
|
172774
|
+
if (trimmedContents.length < requestContents.length) {
|
|
172775
|
+
debugLogger25.warn(`NO_RESPONSE_TEXT: retrying with trimmed context (removed ${requestContents.length - trimmedContents.length} tool-error messages)`);
|
|
172776
|
+
try {
|
|
172777
|
+
const stream2 = await self2.makeApiCallAndProcessStream(model, trimmedContents, params, prompt_id);
|
|
172778
|
+
for await (const chunk of stream2) {
|
|
172779
|
+
yield { type: StreamEventType.CHUNK, value: chunk };
|
|
172780
|
+
}
|
|
172781
|
+
lastError = null;
|
|
172782
|
+
} catch {
|
|
172783
|
+
}
|
|
172784
|
+
}
|
|
172785
|
+
break;
|
|
172786
|
+
}
|
|
172787
|
+
if (isTransientStreamError) {
|
|
172788
|
+
break;
|
|
172789
|
+
}
|
|
172790
|
+
if (!reactiveCompressionAttempted) {
|
|
172791
|
+
const overflow = getContextLengthExceededInfo(error40);
|
|
172792
|
+
if (overflow.isExceeded) {
|
|
172793
|
+
reactiveCompressionAttempted = true;
|
|
172794
|
+
debugLogger25.warn("Context length exceeded; attempting reactive compression and one retry.");
|
|
172795
|
+
try {
|
|
172796
|
+
const { newHistory, info: info3 } = await new ChatCompressionService().compress(
|
|
172797
|
+
self2,
|
|
172798
|
+
prompt_id,
|
|
172799
|
+
true,
|
|
172800
|
+
// force — bypasses the hasFailedCompressionAttempt guard
|
|
172801
|
+
model,
|
|
172802
|
+
self2.config,
|
|
172803
|
+
false,
|
|
172804
|
+
params.config?.abortSignal
|
|
172805
|
+
);
|
|
172806
|
+
if (info3.compressionStatus === CompressionStatus.COMPRESSED && newHistory) {
|
|
172807
|
+
self2.setHistory(newHistory);
|
|
172808
|
+
self2.config.getFileReadCache().clear();
|
|
172809
|
+
self2.telemetryService?.setLastPromptTokenCount(info3.newTokenCount);
|
|
172810
|
+
requestContents = self2.getHistory(true);
|
|
172811
|
+
debugLogger25.info(`Reactive compression succeeded (${info3.originalTokenCount} -> ${info3.newTokenCount} tokens); retrying.`);
|
|
172812
|
+
attempt--;
|
|
172813
|
+
yield { type: StreamEventType.RETRY };
|
|
172814
|
+
continue;
|
|
172815
|
+
}
|
|
172816
|
+
debugLogger25.warn("Reactive compression did not reduce context; giving up.");
|
|
172817
|
+
} catch (compressionError) {
|
|
172818
|
+
debugLogger25.warn(`Reactive compression failed: ${compressionError instanceof Error ? compressionError.message : String(compressionError)}`);
|
|
172819
|
+
}
|
|
172820
|
+
break;
|
|
172821
|
+
}
|
|
172822
|
+
}
|
|
172823
|
+
const isContentError = error40 instanceof InvalidStreamError;
|
|
172824
|
+
if (isContentError) {
|
|
172825
|
+
if (attempt < INVALID_CONTENT_RETRY_OPTIONS.maxAttempts - 1) {
|
|
172826
|
+
logContentRetry(self2.config, new ContentRetryEvent(attempt, error40.type, INVALID_CONTENT_RETRY_OPTIONS.initialDelayMs, model));
|
|
172827
|
+
await new Promise((res) => setTimeout(res, INVALID_CONTENT_RETRY_OPTIONS.initialDelayMs * (attempt + 1)));
|
|
172828
|
+
continue;
|
|
172829
|
+
}
|
|
172830
|
+
}
|
|
172831
|
+
break;
|
|
172832
|
+
}
|
|
172670
172833
|
}
|
|
172671
|
-
|
|
172672
|
-
|
|
172673
|
-
|
|
172834
|
+
if (lastError) {
|
|
172835
|
+
if (lastError instanceof InvalidStreamError) {
|
|
172836
|
+
const totalAttempts = invalidStreamRetryCount + 1;
|
|
172837
|
+
logContentRetryFailure(self2.config, new ContentRetryFailureEvent(totalAttempts, lastError.type, model));
|
|
172838
|
+
}
|
|
172839
|
+
throw lastError;
|
|
172840
|
+
}
|
|
172841
|
+
} finally {
|
|
172842
|
+
streamDoneResolver();
|
|
172674
172843
|
}
|
|
172675
|
-
}
|
|
172676
|
-
|
|
172677
|
-
|
|
172678
|
-
|
|
172679
|
-
|
|
172680
|
-
|
|
172681
|
-
|
|
172682
|
-
|
|
172683
|
-
const
|
|
172684
|
-
|
|
172685
|
-
|
|
172686
|
-
|
|
172687
|
-
|
|
172688
|
-
|
|
172689
|
-
|
|
172690
|
-
|
|
172691
|
-
|
|
172692
|
-
|
|
172693
|
-
|
|
172694
|
-
|
|
172695
|
-
|
|
172696
|
-
|
|
172697
|
-
|
|
172698
|
-
|
|
172699
|
-
|
|
172700
|
-
|
|
172701
|
-
|
|
172702
|
-
return {
|
|
172703
|
-
newHistory,
|
|
172704
|
-
compressed: true,
|
|
172705
|
-
compressionInputTokenCount: inputTokenCount,
|
|
172706
|
-
compressionOutputTokenCount: outputTokenCount
|
|
172707
|
-
};
|
|
172844
|
+
}();
|
|
172845
|
+
}
|
|
172846
|
+
async makeApiCallAndProcessStream(model, requestContents, params, prompt_id) {
|
|
172847
|
+
const apiCall = /* @__PURE__ */ __name(() => this.config.getContentGenerator().generateContentStream({
|
|
172848
|
+
model,
|
|
172849
|
+
contents: requestContents,
|
|
172850
|
+
config: { ...this.generationConfig, ...params.config }
|
|
172851
|
+
}, prompt_id), "apiCall");
|
|
172852
|
+
const streamResponse2 = await retryWithBackoff(apiCall, {
|
|
172853
|
+
shouldRetryOnError: /* @__PURE__ */ __name((error40) => {
|
|
172854
|
+
if (error40 instanceof Error) {
|
|
172855
|
+
if (isSchemaDepthError(error40.message))
|
|
172856
|
+
return false;
|
|
172857
|
+
if (isInvalidArgumentError(error40.message))
|
|
172858
|
+
return false;
|
|
172859
|
+
}
|
|
172860
|
+
const status = getErrorStatus(error40);
|
|
172861
|
+
if (status === 400)
|
|
172862
|
+
return false;
|
|
172863
|
+
if (status === 429)
|
|
172864
|
+
return true;
|
|
172865
|
+
if (status && status >= 500 && status < 600)
|
|
172866
|
+
return true;
|
|
172867
|
+
return false;
|
|
172868
|
+
}, "shouldRetryOnError")
|
|
172869
|
+
});
|
|
172870
|
+
return this.processStreamResponse(model, streamResponse2);
|
|
172708
172871
|
}
|
|
172709
172872
|
/**
|
|
172710
|
-
*
|
|
172711
|
-
*
|
|
172873
|
+
* Returns the chat history.
|
|
172874
|
+
*
|
|
172875
|
+
* @remarks
|
|
172876
|
+
* The history is a list of contents alternating between user and model.
|
|
172877
|
+
*
|
|
172878
|
+
* There are two types of history:
|
|
172879
|
+
* - The `curated history` contains only the valid turns between user and
|
|
172880
|
+
* model, which will be included in the subsequent requests sent to the model.
|
|
172881
|
+
* - The `comprehensive history` contains all turns, including invalid or
|
|
172882
|
+
* empty model outputs, providing a complete record of the history.
|
|
172883
|
+
*
|
|
172884
|
+
* The history is updated after receiving the response from the model,
|
|
172885
|
+
* for streaming response, it means receiving the last chunk of the response.
|
|
172886
|
+
*
|
|
172887
|
+
* The `comprehensive history` is returned by default. To get the `curated
|
|
172888
|
+
* history`, set the `curated` parameter to `true`.
|
|
172889
|
+
*
|
|
172890
|
+
* @param curated - whether to return the curated history or the comprehensive
|
|
172891
|
+
* history.
|
|
172892
|
+
* @return History contents alternating between user and model for the entire
|
|
172893
|
+
* chat session.
|
|
172712
172894
|
*/
|
|
172713
|
-
|
|
172714
|
-
const
|
|
172715
|
-
|
|
172716
|
-
|
|
172717
|
-
|
|
172718
|
-
|
|
172719
|
-
|
|
172720
|
-
|
|
172721
|
-
|
|
172722
|
-
|
|
172723
|
-
|
|
172724
|
-
|
|
172725
|
-
|
|
172726
|
-
|
|
172895
|
+
getHistory(curated = false) {
|
|
172896
|
+
const history = curated ? extractCuratedHistory2(this.history) : this.history;
|
|
172897
|
+
return structuredClone(history);
|
|
172898
|
+
}
|
|
172899
|
+
/**
|
|
172900
|
+
* Clears the chat history.
|
|
172901
|
+
*/
|
|
172902
|
+
clearHistory() {
|
|
172903
|
+
this.history = [];
|
|
172904
|
+
}
|
|
172905
|
+
/**
|
|
172906
|
+
* Adds a new entry to the chat history.
|
|
172907
|
+
*/
|
|
172908
|
+
addHistory(content) {
|
|
172909
|
+
this.history.push(content);
|
|
172910
|
+
}
|
|
172911
|
+
setHistory(history) {
|
|
172912
|
+
this.history = history;
|
|
172913
|
+
}
|
|
172914
|
+
stripThoughtsFromHistory() {
|
|
172915
|
+
this.history = this.history.map((content) => {
|
|
172916
|
+
if (!content.parts)
|
|
172917
|
+
return content;
|
|
172918
|
+
const filteredParts = content.parts.filter((part) => !(part && typeof part === "object" && "thought" in part && part.thought)).map((part) => {
|
|
172919
|
+
if (part && typeof part === "object" && "thoughtSignature" in part) {
|
|
172920
|
+
const newPart = { ...part };
|
|
172921
|
+
delete newPart.thoughtSignature;
|
|
172922
|
+
return newPart;
|
|
172727
172923
|
}
|
|
172728
|
-
|
|
172729
|
-
|
|
172730
|
-
const compressCharCount = historyToCompress.reduce((sum, c4) => sum + JSON.stringify(c4).length, 0);
|
|
172731
|
-
const totalCharCount = historyForSplit.reduce((sum, c4) => sum + JSON.stringify(c4).length, 0);
|
|
172732
|
-
if (totalCharCount > 0 && compressCharCount / totalCharCount < MIN_COMPRESSION_FRACTION) {
|
|
172924
|
+
return part;
|
|
172925
|
+
});
|
|
172733
172926
|
return {
|
|
172734
|
-
|
|
172735
|
-
|
|
172736
|
-
originalTokenCount,
|
|
172737
|
-
newTokenCount: originalTokenCount,
|
|
172738
|
-
compressionStatus: CompressionStatus.NOOP
|
|
172739
|
-
}
|
|
172927
|
+
...content,
|
|
172928
|
+
parts: filteredParts
|
|
172740
172929
|
};
|
|
172741
|
-
}
|
|
172742
|
-
const summaryResponse = await config2.getContentGenerator().generateContent({
|
|
172743
|
-
model,
|
|
172744
|
-
contents: [
|
|
172745
|
-
...historyToCompress,
|
|
172746
|
-
{
|
|
172747
|
-
role: "user",
|
|
172748
|
-
parts: [
|
|
172749
|
-
{
|
|
172750
|
-
text: "Generate the <summary> now. Be maximally concise \u2014 every token counts."
|
|
172751
|
-
}
|
|
172752
|
-
]
|
|
172753
|
-
}
|
|
172754
|
-
],
|
|
172755
|
-
config: {
|
|
172756
|
-
systemInstruction: getCompressionPrompt()
|
|
172757
|
-
}
|
|
172758
|
-
}, promptId);
|
|
172759
|
-
const summary = getResponseText(summaryResponse) ?? "";
|
|
172760
|
-
const prefixedSummary = summary && summary.trim().length > 0 ? summary.startsWith(COMPRESSED_CONTEXT_PREFIX) ? summary : `${COMPRESSED_CONTEXT_PREFIX}
|
|
172761
|
-
${summary}` : summary;
|
|
172762
|
-
const compressionUsageMetadata = summaryResponse.usageMetadata;
|
|
172763
|
-
const compressionInputTokenCount = compressionUsageMetadata?.promptTokenCount;
|
|
172764
|
-
let compressionOutputTokenCount = compressionUsageMetadata?.candidatesTokenCount;
|
|
172765
|
-
if (compressionOutputTokenCount === void 0 && typeof compressionUsageMetadata?.totalTokenCount === "number" && typeof compressionInputTokenCount === "number") {
|
|
172766
|
-
compressionOutputTokenCount = Math.max(0, compressionUsageMetadata.totalTokenCount - compressionInputTokenCount);
|
|
172767
|
-
}
|
|
172768
|
-
const isSummaryEmpty = !prefixedSummary || prefixedSummary.trim().length === 0;
|
|
172769
|
-
let extraHistory = [];
|
|
172770
|
-
if (!isSummaryEmpty) {
|
|
172771
|
-
extraHistory = [
|
|
172772
|
-
{
|
|
172773
|
-
role: "user",
|
|
172774
|
-
parts: [{ text: prefixedSummary }]
|
|
172775
|
-
},
|
|
172776
|
-
{
|
|
172777
|
-
role: "model",
|
|
172778
|
-
parts: [{ text: "Got it. Thanks for the additional context!" }]
|
|
172779
|
-
},
|
|
172780
|
-
...historyToKeep
|
|
172781
|
-
];
|
|
172782
|
-
}
|
|
172783
|
-
return this.finalizeCompression(isSummaryEmpty ? null : extraHistory, originalTokenCount, compressionInputTokenCount, compressionOutputTokenCount, model, config2, signal, isSummaryEmpty);
|
|
172930
|
+
}).filter((content) => content.parts && content.parts.length > 0);
|
|
172784
172931
|
}
|
|
172785
172932
|
/**
|
|
172786
|
-
*
|
|
172787
|
-
*
|
|
172933
|
+
* Pop all orphaned trailing user entries from chat history.
|
|
172934
|
+
* In a valid conversation the last entry is always a model response;
|
|
172935
|
+
* any trailing user entries are leftovers from a request that failed.
|
|
172788
172936
|
*/
|
|
172789
|
-
|
|
172790
|
-
|
|
172791
|
-
|
|
172792
|
-
|
|
172793
|
-
|
|
172794
|
-
|
|
172795
|
-
|
|
172937
|
+
stripOrphanedUserEntriesFromHistory() {
|
|
172938
|
+
while (this.history.length > 0 && this.history[this.history.length - 1].role === "user") {
|
|
172939
|
+
this.history.pop();
|
|
172940
|
+
}
|
|
172941
|
+
}
|
|
172942
|
+
setTools(tools) {
|
|
172943
|
+
this.generationConfig.tools = tools;
|
|
172944
|
+
}
|
|
172945
|
+
/** Returns a shallow copy of the current generation config (for cache param snapshots). */
|
|
172946
|
+
getGenerationConfig() {
|
|
172947
|
+
return { ...this.generationConfig };
|
|
172948
|
+
}
|
|
172949
|
+
async maybeIncludeSchemaDepthContext(error40) {
|
|
172950
|
+
if (isSchemaDepthError(error40.message) || isInvalidArgumentError(error40.message)) {
|
|
172951
|
+
const tools = this.config.getToolRegistry().getAllTools();
|
|
172952
|
+
const cyclicSchemaTools = [];
|
|
172953
|
+
for (const tool of tools) {
|
|
172954
|
+
if (tool.schema.parametersJsonSchema && hasCycleInSchema(tool.schema.parametersJsonSchema) || tool.schema.parameters && hasCycleInSchema(tool.schema.parameters)) {
|
|
172955
|
+
cyclicSchemaTools.push(tool.displayName);
|
|
172956
|
+
}
|
|
172957
|
+
}
|
|
172958
|
+
if (cyclicSchemaTools.length > 0) {
|
|
172959
|
+
const extraDetails = `
|
|
172960
|
+
|
|
172961
|
+
This error was probably caused by cyclic schema references in one of the following tools, try disabling them with excludeTools:
|
|
172962
|
+
|
|
172963
|
+
- ` + cyclicSchemaTools.join(`
|
|
172964
|
+
- `) + `
|
|
172965
|
+
`;
|
|
172966
|
+
error40.message += extraDetails;
|
|
172796
172967
|
}
|
|
172797
172968
|
}
|
|
172798
|
-
|
|
172799
|
-
|
|
172800
|
-
|
|
172801
|
-
|
|
172802
|
-
|
|
172803
|
-
|
|
172804
|
-
|
|
172805
|
-
|
|
172806
|
-
|
|
172807
|
-
|
|
172808
|
-
|
|
172809
|
-
|
|
172810
|
-
|
|
172969
|
+
}
|
|
172970
|
+
async *processStreamResponse(model, streamResponse2) {
|
|
172971
|
+
const allModelParts = [];
|
|
172972
|
+
let usageMetadata;
|
|
172973
|
+
let hasToolCall2 = false;
|
|
172974
|
+
let hasFinishReason = false;
|
|
172975
|
+
for await (const chunk of streamResponse2) {
|
|
172976
|
+
hasFinishReason ||= chunk?.candidates?.some((candidate) => candidate.finishReason) ?? false;
|
|
172977
|
+
if (isValidResponse2(chunk)) {
|
|
172978
|
+
const content = chunk.candidates?.[0]?.content;
|
|
172979
|
+
if (content?.parts) {
|
|
172980
|
+
if (content.parts.some((part) => part.functionCall)) {
|
|
172981
|
+
hasToolCall2 = true;
|
|
172982
|
+
}
|
|
172983
|
+
allModelParts.push(...content.parts);
|
|
172811
172984
|
}
|
|
172812
|
-
}
|
|
172813
|
-
|
|
172814
|
-
|
|
172815
|
-
|
|
172816
|
-
|
|
172817
|
-
|
|
172818
|
-
newTokenCount: originalTokenCount,
|
|
172819
|
-
compressionStatus: CompressionStatus.COMPRESSION_FAILED_TOKEN_COUNT_ERROR
|
|
172985
|
+
}
|
|
172986
|
+
if (chunk.usageMetadata) {
|
|
172987
|
+
usageMetadata = chunk.usageMetadata;
|
|
172988
|
+
const lastPromptTokenCount = usageMetadata.totalTokenCount || usageMetadata.promptTokenCount;
|
|
172989
|
+
if (lastPromptTokenCount && this.telemetryService) {
|
|
172990
|
+
this.telemetryService.setLastPromptTokenCount(lastPromptTokenCount);
|
|
172820
172991
|
}
|
|
172821
|
-
|
|
172822
|
-
|
|
172823
|
-
return {
|
|
172824
|
-
newHistory: null,
|
|
172825
|
-
info: {
|
|
172826
|
-
originalTokenCount,
|
|
172827
|
-
newTokenCount,
|
|
172828
|
-
compressionStatus: CompressionStatus.COMPRESSION_FAILED_INFLATED_TOKEN_COUNT
|
|
172992
|
+
if (usageMetadata.cachedContentTokenCount && this.telemetryService) {
|
|
172993
|
+
this.telemetryService.setLastCachedContentTokenCount(usageMetadata.cachedContentTokenCount);
|
|
172829
172994
|
}
|
|
172830
|
-
};
|
|
172831
|
-
} else {
|
|
172832
|
-
uiTelemetryService.setLastPromptTokenCount(newTokenCount);
|
|
172833
|
-
try {
|
|
172834
|
-
const permissionMode = String(config2.getApprovalMode());
|
|
172835
|
-
await config2.getHookSystem()?.fireSessionStartEvent(SessionStartSource.Compact, model ?? "", permissionMode, void 0, signal);
|
|
172836
|
-
} catch (err3) {
|
|
172837
|
-
config2.getDebugLogger().warn(`SessionStart hook failed: ${err3}`);
|
|
172838
172995
|
}
|
|
172839
|
-
|
|
172840
|
-
|
|
172841
|
-
|
|
172842
|
-
|
|
172843
|
-
|
|
172844
|
-
|
|
172845
|
-
|
|
172996
|
+
yield chunk;
|
|
172997
|
+
}
|
|
172998
|
+
let thoughtContentPart;
|
|
172999
|
+
const thoughtText = allModelParts.filter((part) => part.thought).map((part) => part.text).join("").trim();
|
|
173000
|
+
if (thoughtText !== "") {
|
|
173001
|
+
thoughtContentPart = {
|
|
173002
|
+
text: thoughtText,
|
|
173003
|
+
thought: true
|
|
172846
173004
|
};
|
|
173005
|
+
const thoughtSignature = allModelParts.filter((part) => part.thoughtSignature && part.thought)?.[0]?.thoughtSignature;
|
|
173006
|
+
if (thoughtContentPart && thoughtSignature) {
|
|
173007
|
+
thoughtContentPart.thoughtSignature = thoughtSignature;
|
|
173008
|
+
}
|
|
172847
173009
|
}
|
|
172848
|
-
|
|
172849
|
-
|
|
172850
|
-
|
|
172851
|
-
|
|
172852
|
-
|
|
172853
|
-
|
|
172854
|
-
|
|
172855
|
-
|
|
172856
|
-
|
|
172857
|
-
|
|
172858
|
-
|
|
172859
|
-
|
|
172860
|
-
|
|
172861
|
-
|
|
172862
|
-
|
|
172863
|
-
|
|
172864
|
-
|
|
172865
|
-
|
|
172866
|
-
|
|
172867
|
-
|
|
172868
|
-
|
|
172869
|
-
|
|
172870
|
-
|
|
172871
|
-
|
|
172872
|
-
|
|
172873
|
-
|
|
172874
|
-
|
|
172875
|
-
|
|
172876
|
-
|
|
172877
|
-
while (keepFromIndex > 0 && preservedTokens < MIN_PRESERVED_TOKENS) {
|
|
172878
|
-
keepFromIndex--;
|
|
172879
|
-
preservedTokens += estimateHistoryTokens([history[keepFromIndex]]);
|
|
173010
|
+
const contentParts = allModelParts.filter((part) => !part.thought);
|
|
173011
|
+
const consolidatedHistoryParts = [];
|
|
173012
|
+
for (const part of contentParts) {
|
|
173013
|
+
const lastPart = consolidatedHistoryParts[consolidatedHistoryParts.length - 1];
|
|
173014
|
+
if (lastPart?.text && isValidNonThoughtTextPart(lastPart) && isValidNonThoughtTextPart(part)) {
|
|
173015
|
+
lastPart.text += part.text;
|
|
173016
|
+
} else if (isValidContentPart(part)) {
|
|
173017
|
+
consolidatedHistoryParts.push(part);
|
|
173018
|
+
}
|
|
173019
|
+
}
|
|
173020
|
+
const contentText = consolidatedHistoryParts.filter((part) => part.text).map((part) => part.text).join("").trim();
|
|
173021
|
+
if (thoughtContentPart || contentText || hasToolCall2 || usageMetadata) {
|
|
173022
|
+
const contextWindowSize = this.config.getContentGeneratorConfig()?.contextWindowSize;
|
|
173023
|
+
this.chatRecordingService?.recordAssistantTurn({
|
|
173024
|
+
model,
|
|
173025
|
+
message: [
|
|
173026
|
+
...thoughtContentPart ? [thoughtContentPart] : [],
|
|
173027
|
+
...contentText ? [{ text: contentText }] : [],
|
|
173028
|
+
...hasToolCall2 ? contentParts.filter((part) => part.functionCall).map((part) => ({ functionCall: part.functionCall })) : []
|
|
173029
|
+
],
|
|
173030
|
+
tokens: usageMetadata,
|
|
173031
|
+
contextWindowSize
|
|
173032
|
+
});
|
|
173033
|
+
}
|
|
173034
|
+
if (!hasToolCall2 && (!hasFinishReason || !contentText)) {
|
|
173035
|
+
if (!hasFinishReason) {
|
|
173036
|
+
throw new InvalidStreamError("Model stream ended without a finish reason.", "NO_FINISH_REASON");
|
|
173037
|
+
} else {
|
|
173038
|
+
throw new InvalidStreamError("Model stream ended with empty response text.", "NO_RESPONSE_TEXT");
|
|
172880
173039
|
}
|
|
172881
|
-
keepFromIndex = adjustIndexForToolPairs(history, keepFromIndex);
|
|
172882
|
-
const preservedTail = history.slice(keepFromIndex);
|
|
172883
|
-
const summaryUserMsg = {
|
|
172884
|
-
role: "user",
|
|
172885
|
-
parts: [{ text: summaryText }]
|
|
172886
|
-
};
|
|
172887
|
-
const summaryAckMsg = {
|
|
172888
|
-
role: "model",
|
|
172889
|
-
parts: [
|
|
172890
|
-
{
|
|
172891
|
-
text: "Understood. I have the session summary and will continue from the current state."
|
|
172892
|
-
}
|
|
172893
|
-
]
|
|
172894
|
-
};
|
|
172895
|
-
const newHistory = [summaryUserMsg, summaryAckMsg, ...preservedTail];
|
|
172896
|
-
const newTokenCount = estimateHistoryTokens(newHistory);
|
|
172897
|
-
if (newTokenCount >= originalTokenCount * 0.9)
|
|
172898
|
-
return null;
|
|
172899
|
-
return {
|
|
172900
|
-
newHistory,
|
|
172901
|
-
info: {
|
|
172902
|
-
originalTokenCount,
|
|
172903
|
-
newTokenCount,
|
|
172904
|
-
compressionStatus: CompressionStatus.COMPRESSED
|
|
172905
|
-
}
|
|
172906
|
-
};
|
|
172907
|
-
} catch {
|
|
172908
|
-
return null;
|
|
172909
173040
|
}
|
|
173041
|
+
this.history.push({
|
|
173042
|
+
role: "model",
|
|
173043
|
+
parts: [
|
|
173044
|
+
...thoughtContentPart ? [thoughtContentPart] : [],
|
|
173045
|
+
...consolidatedHistoryParts
|
|
173046
|
+
]
|
|
173047
|
+
});
|
|
172910
173048
|
}
|
|
172911
173049
|
};
|
|
172912
|
-
__name(
|
|
172913
|
-
__name(
|
|
173050
|
+
__name(isSchemaDepthError, "isSchemaDepthError");
|
|
173051
|
+
__name(isInvalidArgumentError, "isInvalidArgumentError");
|
|
173052
|
+
}
|
|
173053
|
+
});
|
|
173054
|
+
|
|
173055
|
+
// packages/core/dist/src/backgroundShells/notifications.js
|
|
173056
|
+
function escapeXml(text) {
|
|
173057
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
173058
|
+
}
|
|
173059
|
+
function buildBackgroundTaskNotification(task) {
|
|
173060
|
+
const exitLine = task.exitCode !== void 0 && task.exitCode !== null ? `
|
|
173061
|
+
<exit_code>${task.exitCode}</exit_code>` : "";
|
|
173062
|
+
const summary = (() => {
|
|
173063
|
+
const desc2 = task.description || task.command;
|
|
173064
|
+
switch (task.status) {
|
|
173065
|
+
case "completed":
|
|
173066
|
+
return `Background command "${desc2}" completed${task.exitCode != null ? ` (exit code ${task.exitCode})` : ""}.`;
|
|
173067
|
+
case "failed":
|
|
173068
|
+
return `Background command "${desc2}" failed${task.exitCode != null ? ` with exit code ${task.exitCode}` : ""}.`;
|
|
173069
|
+
case "killed":
|
|
173070
|
+
return `Background command "${desc2}" was stopped.`;
|
|
173071
|
+
default:
|
|
173072
|
+
return `Background command "${desc2}" ended in unknown state.`;
|
|
173073
|
+
}
|
|
173074
|
+
})();
|
|
173075
|
+
return [
|
|
173076
|
+
"<task_notification>",
|
|
173077
|
+
`<task_id>${task.id}</task_id>`,
|
|
173078
|
+
`<output_file>${task.outputPath}</output_file>`,
|
|
173079
|
+
`<status>${task.status}</status>${exitLine}`,
|
|
173080
|
+
`<summary>${escapeXml(summary)}</summary>`,
|
|
173081
|
+
"</task_notification>",
|
|
173082
|
+
"",
|
|
173083
|
+
`Read ${task.outputPath} to see the full output.`
|
|
173084
|
+
].join("\n");
|
|
173085
|
+
}
|
|
173086
|
+
var init_notifications = __esm({
|
|
173087
|
+
"packages/core/dist/src/backgroundShells/notifications.js"() {
|
|
173088
|
+
"use strict";
|
|
173089
|
+
init_esbuild_shims();
|
|
173090
|
+
__name(escapeXml, "escapeXml");
|
|
173091
|
+
__name(buildBackgroundTaskNotification, "buildBackgroundTaskNotification");
|
|
172914
173092
|
}
|
|
172915
173093
|
});
|
|
172916
173094
|
|
|
@@ -416607,7 +416785,7 @@ __name(getPackageJson, "getPackageJson");
|
|
|
416607
416785
|
// packages/cli/src/utils/version.ts
|
|
416608
416786
|
async function getCliVersion() {
|
|
416609
416787
|
const pkgJson = await getPackageJson();
|
|
416610
|
-
return "0.
|
|
416788
|
+
return "0.52.0";
|
|
416611
416789
|
}
|
|
416612
416790
|
__name(getCliVersion, "getCliVersion");
|
|
416613
416791
|
|
|
@@ -424807,7 +424985,7 @@ var formatDuration = /* @__PURE__ */ __name((milliseconds) => {
|
|
|
424807
424985
|
|
|
424808
424986
|
// packages/cli/src/generated/git-commit.ts
|
|
424809
424987
|
init_esbuild_shims();
|
|
424810
|
-
var GIT_COMMIT_INFO = "
|
|
424988
|
+
var GIT_COMMIT_INFO = "0f21b967a";
|
|
424811
424989
|
|
|
424812
424990
|
// packages/cli/src/utils/systemInfo.ts
|
|
424813
424991
|
async function getNpmVersion() {
|
|
@@ -493609,7 +493787,7 @@ var QwenAgent = class {
|
|
|
493609
493787
|
async initialize(args2) {
|
|
493610
493788
|
this.clientCapabilities = args2.clientCapabilities;
|
|
493611
493789
|
const authMethods = buildAuthMethods();
|
|
493612
|
-
const version2 = "0.
|
|
493790
|
+
const version2 = "0.52.0";
|
|
493613
493791
|
return {
|
|
493614
493792
|
protocolVersion: PROTOCOL_VERSION,
|
|
493615
493793
|
agentInfo: {
|
|
@@ -494696,11 +494874,8 @@ main().catch((error40) => {
|
|
|
494696
494874
|
*/
|
|
494697
494875
|
/**
|
|
494698
494876
|
* @license
|
|
494699
|
-
* Copyright
|
|
494877
|
+
* Copyright 2026 protoCLI contributors
|
|
494700
494878
|
* SPDX-License-Identifier: Apache-2.0
|
|
494701
|
-
*
|
|
494702
|
-
* Builds the <task_notification> blocks that get prepended to the next
|
|
494703
|
-
* user query so the model sees backgrounded tasks finishing.
|
|
494704
494879
|
*/
|
|
494705
494880
|
/**
|
|
494706
494881
|
* @license
|
|
@@ -494756,6 +494931,14 @@ main().catch((error40) => {
|
|
|
494756
494931
|
* where result payloads are large but the call names / return structure
|
|
494757
494932
|
* still provide useful signal to the model.
|
|
494758
494933
|
*/
|
|
494934
|
+
/**
|
|
494935
|
+
* @license
|
|
494936
|
+
* Copyright 2025 protoLabs Studio
|
|
494937
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
494938
|
+
*
|
|
494939
|
+
* Builds the <task_notification> blocks that get prepended to the next
|
|
494940
|
+
* user query so the model sees backgrounded tasks finishing.
|
|
494941
|
+
*/
|
|
494759
494942
|
/**
|
|
494760
494943
|
* @license
|
|
494761
494944
|
* Copyright 2025 protoLabs Studio
|
|
@@ -494824,11 +495007,6 @@ main().catch((error40) => {
|
|
|
494824
495007
|
* By constructing the forked GeminiChat with identical generationConfig and
|
|
494825
495008
|
* history prefix, the fork automatically benefits from prefix caching.
|
|
494826
495009
|
*/
|
|
494827
|
-
/**
|
|
494828
|
-
* @license
|
|
494829
|
-
* Copyright 2026 protoCLI contributors
|
|
494830
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
494831
|
-
*/
|
|
494832
495010
|
/**
|
|
494833
495011
|
* @license
|
|
494834
495012
|
* Copyright 2025 protoLabs Studio
|