neuralos 3.8.3 → 3.8.4
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/bin/gybackend.cjs +187 -27
- package/package.json +1 -1
package/bin/gybackend.cjs
CHANGED
|
@@ -258654,6 +258654,19 @@ var init_HistorySqliteStore = __esm({
|
|
|
258654
258654
|
lastProfileMaxTokens: row.last_profile_max_tokens ?? void 0
|
|
258655
258655
|
}));
|
|
258656
258656
|
}
|
|
258657
|
+
/**
|
|
258658
|
+
* Every session WITH all messages.
|
|
258659
|
+
*
|
|
258660
|
+
* FREEZE WARNING (v3.8.4): this JSON.parses every message of every session
|
|
258661
|
+
* in one synchronous burst — on this machine's 1.6 GB / multi-session store
|
|
258662
|
+
* that is seconds of blocked event loop (so the UI freezes, because
|
|
258663
|
+
* better-sqlite3 is synchronous and runs on the same thread).
|
|
258664
|
+
*
|
|
258665
|
+
* It is only acceptable for genuinely whole-store work. Callers that merely
|
|
258666
|
+
* need session *lists* must use `listChatSessionSummaries()` (COUNT only, no
|
|
258667
|
+
* message bodies) — see `searchChatHistoryBounded` in historySearch.ts,
|
|
258668
|
+
* which replaced the old bridge call to this method.
|
|
258669
|
+
*/
|
|
258657
258670
|
listChatSessions() {
|
|
258658
258671
|
return this.listChatSessionSummaries().map((summary) => this.loadChatSession(summary.id)).filter(
|
|
258659
258672
|
(session) => session !== null
|
|
@@ -262693,7 +262706,8 @@ __export(historySearch_exports, {
|
|
|
262693
262706
|
extractMessageText: () => extractMessageText2,
|
|
262694
262707
|
findMatches: () => findMatches,
|
|
262695
262708
|
normalizeMessages: () => normalizeMessages,
|
|
262696
|
-
searchChatHistory: () => searchChatHistory
|
|
262709
|
+
searchChatHistory: () => searchChatHistory,
|
|
262710
|
+
searchChatHistoryBounded: () => searchChatHistoryBounded
|
|
262697
262711
|
});
|
|
262698
262712
|
function extractMessageText2(data) {
|
|
262699
262713
|
if (!data || typeof data !== "object") return "";
|
|
@@ -262755,6 +262769,39 @@ function normalizeMessages(messages) {
|
|
|
262755
262769
|
if (typeof messages === "object") return Object.values(messages);
|
|
262756
262770
|
return [];
|
|
262757
262771
|
}
|
|
262772
|
+
async function searchChatHistoryBounded(loadSummaries, loadSession, query, options = {}) {
|
|
262773
|
+
const trimmed = (query ?? "").trim();
|
|
262774
|
+
if (!trimmed) {
|
|
262775
|
+
return { query: trimmed, totalSessions: 0, totalMatches: 0, sessions: [], truncated: false };
|
|
262776
|
+
}
|
|
262777
|
+
const summaries = loadSummaries();
|
|
262778
|
+
const results = [];
|
|
262779
|
+
const yieldTick = () => new Promise((resolve2) => setTimeout(resolve2, 0));
|
|
262780
|
+
for (const summary of summaries) {
|
|
262781
|
+
const session = loadSession(summary.id);
|
|
262782
|
+
if (session) {
|
|
262783
|
+
const hit = searchChatHistory([session], trimmed, {
|
|
262784
|
+
...options,
|
|
262785
|
+
// Per-session we want ALL snippets; the cap is applied per session by
|
|
262786
|
+
// searchChatHistory, and truncated is recomputed globally below.
|
|
262787
|
+
sessionLimit: 1
|
|
262788
|
+
});
|
|
262789
|
+
if (hit.sessions.length > 0) results.push(hit.sessions[0]);
|
|
262790
|
+
}
|
|
262791
|
+
await yieldTick();
|
|
262792
|
+
}
|
|
262793
|
+
results.sort((a, b) => b.matchCount - a.matchCount || b.updatedAt - a.updatedAt);
|
|
262794
|
+
const sessionLimit = options.sessionLimit ?? DEFAULT_SESSION_LIMIT;
|
|
262795
|
+
const totalMatches = results.reduce((sum, s) => sum + s.matchCount, 0);
|
|
262796
|
+
const truncated = results.length > sessionLimit;
|
|
262797
|
+
return {
|
|
262798
|
+
query: trimmed,
|
|
262799
|
+
totalSessions: results.length,
|
|
262800
|
+
totalMatches,
|
|
262801
|
+
sessions: results.slice(0, sessionLimit),
|
|
262802
|
+
truncated
|
|
262803
|
+
};
|
|
262804
|
+
}
|
|
262758
262805
|
function searchChatHistory(sessions, query, options = {}) {
|
|
262759
262806
|
const sessionLimit = options.sessionLimit ?? DEFAULT_SESSION_LIMIT;
|
|
262760
262807
|
const snippetLimit = options.snippetLimit ?? DEFAULT_SNIPPET_LIMIT;
|
|
@@ -347476,19 +347523,19 @@ async function runFileMutationTool(args, context2, toolName, unavailableOperatio
|
|
|
347476
347523
|
if (context2.signal?.aborted) throw new Error("AbortError");
|
|
347477
347524
|
const resolved = resolveTerminalForTool(context2, tabIdOrName);
|
|
347478
347525
|
if (!resolved.ok) {
|
|
347479
|
-
const
|
|
347526
|
+
const errorText2 = resolved.message;
|
|
347480
347527
|
sendEvent(sessionId, {
|
|
347481
347528
|
messageId,
|
|
347482
347529
|
type: "tool_call",
|
|
347483
347530
|
toolName,
|
|
347484
347531
|
input: JSON.stringify(args),
|
|
347485
|
-
output:
|
|
347532
|
+
output: errorText2
|
|
347486
347533
|
});
|
|
347487
|
-
return
|
|
347534
|
+
return errorText2;
|
|
347488
347535
|
}
|
|
347489
347536
|
const bestMatch = resolved.terminal;
|
|
347490
347537
|
if (!resolved.snapshot.canUseFilesystem) {
|
|
347491
|
-
const
|
|
347538
|
+
const errorText2 = bestMatch.capabilities?.supportsFilesystem !== true && resolved.snapshot.runtimeState === "ready" ? `Error: Terminal tab "${bestMatch.title || bestMatch.id}" (id=${bestMatch.id}, type=${bestMatch.type}) does not support filesystem operations.` : formatTerminalUnavailableForTool(
|
|
347492
347539
|
resolved.snapshot,
|
|
347493
347540
|
unavailableOperation
|
|
347494
347541
|
);
|
|
@@ -347496,12 +347543,12 @@ async function runFileMutationTool(args, context2, toolName, unavailableOperatio
|
|
|
347496
347543
|
messageId,
|
|
347497
347544
|
type: "file_edit",
|
|
347498
347545
|
toolName,
|
|
347499
|
-
output:
|
|
347546
|
+
output: errorText2,
|
|
347500
347547
|
filePath: filePathInput,
|
|
347501
347548
|
action: "error",
|
|
347502
347549
|
diff: ""
|
|
347503
347550
|
});
|
|
347504
|
-
return
|
|
347551
|
+
return errorText2;
|
|
347505
347552
|
}
|
|
347506
347553
|
let outputText = "";
|
|
347507
347554
|
let diffText2 = "";
|
|
@@ -349677,15 +349724,15 @@ async function readCommandOutput(args, context2) {
|
|
|
349677
349724
|
abortIfNeeded(context2.signal);
|
|
349678
349725
|
const terminalResolution = resolveTerminalForTool(context2, tabIdOrName);
|
|
349679
349726
|
if (!terminalResolution.ok) {
|
|
349680
|
-
const
|
|
349727
|
+
const errorText2 = terminalResolution.message;
|
|
349681
349728
|
sendEvent(sessionId, {
|
|
349682
349729
|
messageId,
|
|
349683
349730
|
type: "tool_call",
|
|
349684
349731
|
toolName: "read_command_output",
|
|
349685
349732
|
input: JSON.stringify(args ?? {}),
|
|
349686
|
-
output:
|
|
349733
|
+
output: errorText2
|
|
349687
349734
|
});
|
|
349688
|
-
return
|
|
349735
|
+
return errorText2;
|
|
349689
349736
|
}
|
|
349690
349737
|
const bestMatch = terminalResolution.terminal;
|
|
349691
349738
|
const task2 = terminalService.getCommandTask(bestMatch.id, history_command_match_id);
|
|
@@ -349695,16 +349742,16 @@ async function readCommandOutput(args, context2) {
|
|
|
349695
349742
|
const started = new Date(t.startTime).toISOString();
|
|
349696
349743
|
return `- id: ${t.id}, status: ${t.status}, command: ${t.command}, started: ${started}`;
|
|
349697
349744
|
}).join("\n") : "(No command history for this terminal)";
|
|
349698
|
-
const
|
|
349745
|
+
const errorText2 = `Error: history_command_match_id "${history_command_match_id}" not found in terminal "${bestMatch.title || bestMatch.id}".
|
|
349699
349746
|
${history2}`;
|
|
349700
349747
|
sendEvent(sessionId, {
|
|
349701
349748
|
messageId,
|
|
349702
349749
|
type: "tool_call",
|
|
349703
349750
|
toolName: "read_command_output",
|
|
349704
349751
|
input: JSON.stringify(args ?? {}),
|
|
349705
|
-
output:
|
|
349752
|
+
output: errorText2
|
|
349706
349753
|
});
|
|
349707
|
-
return
|
|
349754
|
+
return errorText2;
|
|
349708
349755
|
}
|
|
349709
349756
|
const output = task2.output || "";
|
|
349710
349757
|
const isRunning = task2.status === "running";
|
|
@@ -349740,19 +349787,19 @@ async function writeStdin(args, context2) {
|
|
|
349740
349787
|
abortIfNeeded(context2.signal);
|
|
349741
349788
|
const terminalResolution = resolveTerminalForTool(context2, tabIdOrName);
|
|
349742
349789
|
if (!terminalResolution.ok) {
|
|
349743
|
-
const
|
|
349790
|
+
const errorText2 = terminalResolution.message;
|
|
349744
349791
|
sendEvent(sessionId, {
|
|
349745
349792
|
messageId,
|
|
349746
349793
|
type: "tool_call",
|
|
349747
349794
|
toolName: "write_stdin",
|
|
349748
349795
|
input: JSON.stringify(sequence ?? []),
|
|
349749
|
-
output:
|
|
349796
|
+
output: errorText2
|
|
349750
349797
|
});
|
|
349751
|
-
return
|
|
349798
|
+
return errorText2;
|
|
349752
349799
|
}
|
|
349753
349800
|
const bestMatch = terminalResolution.terminal;
|
|
349754
349801
|
if (!terminalResolution.snapshot.canWrite) {
|
|
349755
|
-
const
|
|
349802
|
+
const errorText2 = formatTerminalUnavailableForTool(
|
|
349756
349803
|
terminalResolution.snapshot,
|
|
349757
349804
|
"send input to this terminal"
|
|
349758
349805
|
);
|
|
@@ -349761,9 +349808,9 @@ async function writeStdin(args, context2) {
|
|
|
349761
349808
|
type: "tool_call",
|
|
349762
349809
|
toolName: "write_stdin",
|
|
349763
349810
|
input: JSON.stringify(sequence ?? []),
|
|
349764
|
-
output:
|
|
349811
|
+
output: errorText2
|
|
349765
349812
|
});
|
|
349766
|
-
return
|
|
349813
|
+
return errorText2;
|
|
349767
349814
|
}
|
|
349768
349815
|
const commandText = (sequence ?? []).join("");
|
|
349769
349816
|
const allowed = await checkCommandPolicy(commandText, "write_stdin", context2);
|
|
@@ -366057,6 +366104,9 @@ async function invokeWithRetry(fn, maxRetries = 4, delays = [1e3, 2e3, 4e3, 6e3]
|
|
|
366057
366104
|
if (isAbortError3(error40)) {
|
|
366058
366105
|
throw error40;
|
|
366059
366106
|
}
|
|
366107
|
+
if (!isRetryableError(error40)) {
|
|
366108
|
+
throw error40;
|
|
366109
|
+
}
|
|
366060
366110
|
if (attempt < maxRetries - 1) {
|
|
366061
366111
|
const delay = delays[attempt];
|
|
366062
366112
|
console.warn(`[AgentService] Model invocation failed (Attempt ${attempt + 1}/${maxRetries}). Error: ${error40.message}. Retrying in ${delay}ms...`);
|
|
@@ -366075,8 +366125,80 @@ async function invokeWithRetry(fn, maxRetries = 4, delays = [1e3, 2e3, 4e3, 6e3]
|
|
|
366075
366125
|
}
|
|
366076
366126
|
throw lastError;
|
|
366077
366127
|
}
|
|
366128
|
+
function errorText(error40) {
|
|
366129
|
+
const parts = [];
|
|
366130
|
+
if (typeof error40?.message === "string") parts.push(error40.message);
|
|
366131
|
+
if (typeof error40?.error?.message === "string") parts.push(error40.error.message);
|
|
366132
|
+
if (typeof error40?.code === "string") parts.push(error40.code);
|
|
366133
|
+
if (typeof error40?.status === "number") parts.push(String(error40.status));
|
|
366134
|
+
if (typeof error40?.statusCode === "number") parts.push(String(error40.statusCode));
|
|
366135
|
+
if (typeof error40?.cause?.code === "string") parts.push(error40.cause.code);
|
|
366136
|
+
return parts.join(" ").toLowerCase();
|
|
366137
|
+
}
|
|
366078
366138
|
function isRetryableError(error40) {
|
|
366079
|
-
|
|
366139
|
+
if (isAbortError3(error40)) return false;
|
|
366140
|
+
const text = errorText(error40);
|
|
366141
|
+
if (!text) return false;
|
|
366142
|
+
const finishMatch = text.match(/finish_reason=([^.)]*)/);
|
|
366143
|
+
if (finishMatch) {
|
|
366144
|
+
const reasons = finishMatch[1].split(/[,\s]+/).filter(Boolean);
|
|
366145
|
+
if (reasons.includes("error")) return true;
|
|
366146
|
+
const deterministicReasons = /* @__PURE__ */ new Set(["length", "content_filter"]);
|
|
366147
|
+
if (reasons.length > 0 && reasons.every((r) => deterministicReasons.has(r))) {
|
|
366148
|
+
return false;
|
|
366149
|
+
}
|
|
366150
|
+
}
|
|
366151
|
+
const deterministic = [
|
|
366152
|
+
"empty unusable response",
|
|
366153
|
+
"cannot read properties of undefined",
|
|
366154
|
+
"cannot read properties of null",
|
|
366155
|
+
"is not a function",
|
|
366156
|
+
"bad request",
|
|
366157
|
+
"invalid_request",
|
|
366158
|
+
"validation",
|
|
366159
|
+
"context_length",
|
|
366160
|
+
"context length",
|
|
366161
|
+
"maximum context",
|
|
366162
|
+
"too many tokens",
|
|
366163
|
+
"unsupported",
|
|
366164
|
+
"malformed",
|
|
366165
|
+
"unauthorized",
|
|
366166
|
+
"forbidden",
|
|
366167
|
+
"model_not_found",
|
|
366168
|
+
"insufficient_quota",
|
|
366169
|
+
"invalid api key",
|
|
366170
|
+
"invalid_api_key"
|
|
366171
|
+
];
|
|
366172
|
+
if (deterministic.some((needle) => text.includes(needle))) return false;
|
|
366173
|
+
const transient = [
|
|
366174
|
+
"econnreset",
|
|
366175
|
+
"econnrefused",
|
|
366176
|
+
"etimedout",
|
|
366177
|
+
"esockettimedout",
|
|
366178
|
+
"epipe",
|
|
366179
|
+
"enotfound",
|
|
366180
|
+
"eai_again",
|
|
366181
|
+
"socket hang up",
|
|
366182
|
+
"network",
|
|
366183
|
+
"fetch failed",
|
|
366184
|
+
"connection reset",
|
|
366185
|
+
"connection error",
|
|
366186
|
+
"premature close",
|
|
366187
|
+
"timed out",
|
|
366188
|
+
"timeout",
|
|
366189
|
+
"terminated",
|
|
366190
|
+
"502",
|
|
366191
|
+
"503",
|
|
366192
|
+
"504",
|
|
366193
|
+
"429",
|
|
366194
|
+
"rate limit",
|
|
366195
|
+
"overloaded",
|
|
366196
|
+
"server error",
|
|
366197
|
+
"bad gateway",
|
|
366198
|
+
"service unavailable",
|
|
366199
|
+
"gateway timeout"
|
|
366200
|
+
];
|
|
366201
|
+
return transient.some((needle) => text.includes(needle));
|
|
366080
366202
|
}
|
|
366081
366203
|
function extractErrorDetails(error40) {
|
|
366082
366204
|
let details = "";
|
|
@@ -366281,6 +366403,28 @@ function getStreamedResponseModelName(response, rawChunks) {
|
|
|
366281
366403
|
(candidate) => typeof candidate === "string" && candidate.trim().length > 0
|
|
366282
366404
|
);
|
|
366283
366405
|
}
|
|
366406
|
+
var KNOWN_FINISH_REASONS = [
|
|
366407
|
+
"stop",
|
|
366408
|
+
"length",
|
|
366409
|
+
"tool_calls",
|
|
366410
|
+
"content_filter",
|
|
366411
|
+
"function_call",
|
|
366412
|
+
"error"
|
|
366413
|
+
];
|
|
366414
|
+
function normalizeFinishReason(reason) {
|
|
366415
|
+
if (typeof reason !== "string") return "";
|
|
366416
|
+
const trimmed = reason.trim();
|
|
366417
|
+
if (!trimmed) return "";
|
|
366418
|
+
const lowered = trimmed.toLowerCase();
|
|
366419
|
+
for (const known of KNOWN_FINISH_REASONS) {
|
|
366420
|
+
for (let repeats = 5; repeats >= 2; repeats--) {
|
|
366421
|
+
if (lowered === known.repeat(repeats)) {
|
|
366422
|
+
return known;
|
|
366423
|
+
}
|
|
366424
|
+
}
|
|
366425
|
+
}
|
|
366426
|
+
return trimmed;
|
|
366427
|
+
}
|
|
366284
366428
|
function isEmptyMalformedToolCallFinish(response, rawChunks) {
|
|
366285
366429
|
if (!hasToolCallFinishReason(response, rawChunks)) return false;
|
|
366286
366430
|
if (hasAnyToolCallPayload(response, rawChunks)) return false;
|
|
@@ -366338,7 +366482,7 @@ function extractRawResponseMetadata(rawChunk) {
|
|
|
366338
366482
|
}
|
|
366339
366483
|
function getRawFinishReason(rawChunk) {
|
|
366340
366484
|
const choices = Array.isArray(rawChunk?.choices) ? rawChunk.choices : [];
|
|
366341
|
-
return choices.map((choice) => choice?.finish_reason ?? choice?.finishReason).find((reason) => hasNonEmptyString(reason));
|
|
366485
|
+
return choices.map((choice) => normalizeFinishReason(choice?.finish_reason ?? choice?.finishReason)).find((reason) => hasNonEmptyString(reason));
|
|
366342
366486
|
}
|
|
366343
366487
|
function getFinishReasons(response, rawChunks) {
|
|
366344
366488
|
const candidates = [
|
|
@@ -366352,7 +366496,7 @@ function getFinishReasons(response, rawChunks) {
|
|
|
366352
366496
|
) : []
|
|
366353
366497
|
)
|
|
366354
366498
|
];
|
|
366355
|
-
return candidates.filter(hasNonEmptyString);
|
|
366499
|
+
return candidates.map((c) => normalizeFinishReason(c)).filter(hasNonEmptyString);
|
|
366356
366500
|
}
|
|
366357
366501
|
function getMessageType(message) {
|
|
366358
366502
|
const type2 = typeof message?._getType === "function" ? message._getType() : message?.type;
|
|
@@ -374938,20 +375082,24 @@ var WebSocketGatewayAdapter = class {
|
|
|
374938
375082
|
}
|
|
374939
375083
|
case "history:search": {
|
|
374940
375084
|
const bridge = this.options.historyBridge;
|
|
374941
|
-
if (!bridge?.getAllSessions) {
|
|
375085
|
+
if (!bridge?.searchBounded && !bridge?.getAllSessions) {
|
|
374942
375086
|
throw new WebSocketRpcError(
|
|
374943
375087
|
"METHOD_NOT_FOUND",
|
|
374944
375088
|
"history:search is not available on this gateway (no history bridge)."
|
|
374945
375089
|
);
|
|
374946
375090
|
}
|
|
374947
|
-
const { searchChatHistory: searchChatHistory2 } = await Promise.resolve().then(() => (init_historySearch(), historySearch_exports));
|
|
374948
|
-
const sessions = await bridge.getAllSessions();
|
|
374949
375091
|
const query = this.readStringParam(params, "query");
|
|
374950
375092
|
const wholeWord = params?.wholeWord === true;
|
|
374951
375093
|
const includeTitles = params?.includeTitles !== false;
|
|
374952
375094
|
const sessionLimit = typeof params?.sessionLimit === "number" ? params.sessionLimit : void 0;
|
|
374953
375095
|
const snippetLimit = typeof params?.snippetLimit === "number" ? params.snippetLimit : void 0;
|
|
374954
|
-
|
|
375096
|
+
const options = { wholeWord, includeTitles, sessionLimit, snippetLimit };
|
|
375097
|
+
if (bridge.searchBounded) {
|
|
375098
|
+
return await bridge.searchBounded(query, options);
|
|
375099
|
+
}
|
|
375100
|
+
const { searchChatHistory: searchChatHistory2 } = await Promise.resolve().then(() => (init_historySearch(), historySearch_exports));
|
|
375101
|
+
const sessions = await bridge.getAllSessions();
|
|
375102
|
+
return searchChatHistory2(sessions, query, options);
|
|
374955
375103
|
}
|
|
374956
375104
|
case "settings:listBackups": {
|
|
374957
375105
|
const bridge = this.options.settingsBridge;
|
|
@@ -387031,6 +387179,7 @@ var HistoryStorageMigration = class {
|
|
|
387031
387179
|
|
|
387032
387180
|
// ../../packages/backend/src/runtimes/gybackend/startGyBackend.ts
|
|
387033
387181
|
init_HistorySqliteStore();
|
|
387182
|
+
init_historySearch();
|
|
387034
387183
|
|
|
387035
387184
|
// ../../packages/backend/src/services/AgentSettingProfileService.ts
|
|
387036
387185
|
var AgentSettingProfileService = class {
|
|
@@ -398044,7 +398193,18 @@ async function startGyBackend() {
|
|
|
398044
398193
|
);
|
|
398045
398194
|
}
|
|
398046
398195
|
return agentService.getAllChatHistory() ?? [];
|
|
398047
|
-
}
|
|
398196
|
+
},
|
|
398197
|
+
// v3.8.4 FREEZE FIX: the gateway's history:search called
|
|
398198
|
+
// `getAllSessions()`, which JSON.parses EVERY message of EVERY
|
|
398199
|
+
// session synchronously — seconds of blocked event loop on a large
|
|
398200
|
+
// store, freezing the UI. This searches one session at a time and
|
|
398201
|
+
// yields between them, so nothing blocks.
|
|
398202
|
+
searchBounded: async (query, options) => searchChatHistoryBounded(
|
|
398203
|
+
() => historyStore.listChatSessionSummaries(),
|
|
398204
|
+
(id) => historyStore.loadChatSession(id),
|
|
398205
|
+
query,
|
|
398206
|
+
options ?? {}
|
|
398207
|
+
)
|
|
398048
398208
|
},
|
|
398049
398209
|
commandPolicyBridge: {
|
|
398050
398210
|
getLists: async () => {
|