opencode-sonarqube 2.0.1 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +84 -47
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4787,7 +4787,10 @@ class SonarQubeClient {
|
|
|
4787
4787
|
return this.request("/api/authentication/validate");
|
|
4788
4788
|
}
|
|
4789
4789
|
async getVersion() {
|
|
4790
|
-
const
|
|
4790
|
+
const url2 = buildUrl(this.baseUrl, "/api/server/version");
|
|
4791
|
+
const response = await fetch(url2, {
|
|
4792
|
+
headers: { Authorization: buildAuthHeader(this.auth) }
|
|
4793
|
+
});
|
|
4791
4794
|
return response.text();
|
|
4792
4795
|
}
|
|
4793
4796
|
async healthCheck() {
|
|
@@ -4987,10 +4990,8 @@ async function loadProjectState(directory) {
|
|
|
4987
4990
|
async function saveProjectState(directory, state) {
|
|
4988
4991
|
const stateDir = getStateDir(directory);
|
|
4989
4992
|
const statePath = getStatePath(directory);
|
|
4990
|
-
const
|
|
4991
|
-
|
|
4992
|
-
await Bun.write(`${stateDir}/.gitkeep`, "");
|
|
4993
|
-
}
|
|
4993
|
+
const { mkdir } = await import("node:fs/promises");
|
|
4994
|
+
await mkdir(stateDir, { recursive: true });
|
|
4994
4995
|
const content = JSON.stringify(state, null, 2);
|
|
4995
4996
|
await Bun.write(statePath, content);
|
|
4996
4997
|
logger5.info("Saved project state", { projectKey: state.projectKey });
|
|
@@ -19600,32 +19601,37 @@ function formatAnalysisResult(result) {
|
|
|
19600
19601
|
init_bootstrap();
|
|
19601
19602
|
init_logger();
|
|
19602
19603
|
var logger7 = new Logger("sonarqube-hooks");
|
|
19603
|
-
var editedFiles = new Set;
|
|
19604
|
-
var lastAnalysisTime = 0;
|
|
19605
19604
|
var ANALYSIS_COOLDOWN_MS = 5 * 60 * 1000;
|
|
19606
|
-
|
|
19605
|
+
function createHookState() {
|
|
19606
|
+
return {
|
|
19607
|
+
editedFiles: new Set,
|
|
19608
|
+
lastAnalysisTime: 0,
|
|
19609
|
+
bootstrapInProgress: false
|
|
19610
|
+
};
|
|
19611
|
+
}
|
|
19612
|
+
var activeState = createHookState();
|
|
19607
19613
|
function isAnalysisEnabled(config3) {
|
|
19608
19614
|
return config3 !== null && config3.level !== "off" && config3.autoAnalyze;
|
|
19609
19615
|
}
|
|
19610
|
-
function isInCooldown() {
|
|
19616
|
+
function isInCooldown(state) {
|
|
19611
19617
|
const now = Date.now();
|
|
19612
|
-
return now - lastAnalysisTime < ANALYSIS_COOLDOWN_MS;
|
|
19618
|
+
return now - state.lastAnalysisTime < ANALYSIS_COOLDOWN_MS;
|
|
19613
19619
|
}
|
|
19614
|
-
async function handleBootstrap(config3, directory) {
|
|
19615
|
-
if (bootstrapInProgress) {
|
|
19620
|
+
async function handleBootstrap(config3, directory, hookState) {
|
|
19621
|
+
if (hookState.bootstrapInProgress) {
|
|
19616
19622
|
logger7.debug("Bootstrap already in progress");
|
|
19617
19623
|
return;
|
|
19618
19624
|
}
|
|
19619
19625
|
logger7.info("First run detected - initializing SonarQube integration");
|
|
19620
|
-
bootstrapInProgress = true;
|
|
19626
|
+
hookState.bootstrapInProgress = true;
|
|
19621
19627
|
try {
|
|
19622
19628
|
const result = await bootstrap({ config: config3, directory });
|
|
19623
|
-
bootstrapInProgress = false;
|
|
19629
|
+
hookState.bootstrapInProgress = false;
|
|
19624
19630
|
return result.success ? formatBootstrapMessage(result) : `**SonarQube Setup Failed**
|
|
19625
19631
|
|
|
19626
19632
|
${result.message}`;
|
|
19627
19633
|
} catch (error45) {
|
|
19628
|
-
bootstrapInProgress = false;
|
|
19634
|
+
hookState.bootstrapInProgress = false;
|
|
19629
19635
|
logger7.error("Bootstrap failed", { error: String(error45) });
|
|
19630
19636
|
const errorMsg = error45 instanceof Error ? error45.message : String(error45);
|
|
19631
19637
|
return `**SonarQube Setup Error**
|
|
@@ -19633,7 +19639,7 @@ ${result.message}`;
|
|
|
19633
19639
|
${errorMsg}`;
|
|
19634
19640
|
}
|
|
19635
19641
|
}
|
|
19636
|
-
async function performAnalysis(config3, state, directory) {
|
|
19642
|
+
async function performAnalysis(config3, state, directory, hookState) {
|
|
19637
19643
|
const projectKey = state.projectKey;
|
|
19638
19644
|
const projectName = config3.projectName ?? projectKey;
|
|
19639
19645
|
const result = await runAnalysis(config3, state, {
|
|
@@ -19642,7 +19648,9 @@ async function performAnalysis(config3, state, directory) {
|
|
|
19642
19648
|
sources: config3.sources,
|
|
19643
19649
|
tests: config3.tests
|
|
19644
19650
|
}, directory);
|
|
19645
|
-
|
|
19651
|
+
if (result.success) {
|
|
19652
|
+
hookState.editedFiles.clear();
|
|
19653
|
+
}
|
|
19646
19654
|
return formatAnalysisOutput(result, config3);
|
|
19647
19655
|
}
|
|
19648
19656
|
function formatAnalysisOutput(result, config3) {
|
|
@@ -19667,7 +19675,7 @@ function formatActionPrompt(result, _config) {
|
|
|
19667
19675
|
|
|
19668
19676
|
**Action Required:** Found ${blockerCount} blocker(s) and ${criticalCount} critical issue(s). Please review and fix these issues before continuing.`;
|
|
19669
19677
|
}
|
|
19670
|
-
function createIdleHook(getConfig, getDirectory) {
|
|
19678
|
+
function createIdleHook(getConfig, getDirectory, hookState = activeState) {
|
|
19671
19679
|
return async function handleSessionIdle() {
|
|
19672
19680
|
const rawConfig = getConfig()?.["sonarqube"];
|
|
19673
19681
|
const config3 = loadConfig(rawConfig);
|
|
@@ -19676,25 +19684,25 @@ function createIdleHook(getConfig, getDirectory) {
|
|
|
19676
19684
|
}
|
|
19677
19685
|
const directory = getDirectory();
|
|
19678
19686
|
if (await needsBootstrap(directory)) {
|
|
19679
|
-
return handleBootstrap(config3, directory);
|
|
19687
|
+
return handleBootstrap(config3, directory, hookState);
|
|
19680
19688
|
}
|
|
19681
|
-
if (isInCooldown()) {
|
|
19689
|
+
if (isInCooldown(hookState)) {
|
|
19682
19690
|
logger7.debug("Skipping auto-analysis (cooldown)");
|
|
19683
19691
|
return;
|
|
19684
19692
|
}
|
|
19685
|
-
if (editedFiles.size === 0) {
|
|
19693
|
+
if (hookState.editedFiles.size === 0) {
|
|
19686
19694
|
logger7.debug("Skipping auto-analysis (no edited files)");
|
|
19687
19695
|
return;
|
|
19688
19696
|
}
|
|
19689
19697
|
logger7.info("Session idle - triggering auto-analysis");
|
|
19690
|
-
lastAnalysisTime = Date.now();
|
|
19698
|
+
hookState.lastAnalysisTime = Date.now();
|
|
19691
19699
|
try {
|
|
19692
19700
|
const state = await getProjectState(directory);
|
|
19693
19701
|
if (!state) {
|
|
19694
19702
|
logger7.warn("No project state found, cannot run analysis");
|
|
19695
19703
|
return;
|
|
19696
19704
|
}
|
|
19697
|
-
return await performAnalysis(config3, state, directory);
|
|
19705
|
+
return await performAnalysis(config3, state, directory, hookState);
|
|
19698
19706
|
} catch (error45) {
|
|
19699
19707
|
logger7.error(`Auto-analysis failed: ${error45}`);
|
|
19700
19708
|
return;
|
|
@@ -19732,22 +19740,26 @@ var IGNORED_FILE_PATTERNS = [
|
|
|
19732
19740
|
function shouldIgnoreFile(filePath) {
|
|
19733
19741
|
return IGNORED_FILE_PATTERNS.some((pattern) => pattern.test(filePath));
|
|
19734
19742
|
}
|
|
19735
|
-
function createFileEditedHook() {
|
|
19743
|
+
function createFileEditedHook(hookState = activeState) {
|
|
19736
19744
|
return function handleFileEdited(input) {
|
|
19737
19745
|
const { filePath } = input;
|
|
19738
19746
|
if (!shouldIgnoreFile(filePath)) {
|
|
19739
|
-
editedFiles.add(filePath);
|
|
19747
|
+
hookState.editedFiles.add(filePath);
|
|
19748
|
+
activeState = hookState;
|
|
19740
19749
|
logger7.debug(`Tracked edited file: ${filePath}`);
|
|
19741
19750
|
}
|
|
19742
19751
|
};
|
|
19743
19752
|
}
|
|
19744
19753
|
function getEditedFiles() {
|
|
19745
|
-
return Array.from(editedFiles);
|
|
19754
|
+
return Array.from(activeState.editedFiles);
|
|
19746
19755
|
}
|
|
19747
19756
|
function createHooks(getConfig, getDirectory) {
|
|
19757
|
+
const hookState = createHookState();
|
|
19758
|
+
activeState = hookState;
|
|
19748
19759
|
return {
|
|
19749
|
-
sessionIdle: createIdleHook(getConfig, getDirectory),
|
|
19750
|
-
fileEdited: createFileEditedHook()
|
|
19760
|
+
sessionIdle: createIdleHook(getConfig, getDirectory, hookState),
|
|
19761
|
+
fileEdited: createFileEditedHook(hookState),
|
|
19762
|
+
getEditedFiles: () => Array.from(hookState.editedFiles)
|
|
19751
19763
|
};
|
|
19752
19764
|
}
|
|
19753
19765
|
|
|
@@ -20495,7 +20507,8 @@ var SonarQubeToolArgsSchema = exports_external2.object({
|
|
|
20495
20507
|
});
|
|
20496
20508
|
async function executeSonarQubeTool(args, context) {
|
|
20497
20509
|
const directory = context.directory ?? process.cwd();
|
|
20498
|
-
const
|
|
20510
|
+
const rawConfig = context.config?.["sonarqube"] ?? context.config;
|
|
20511
|
+
const config3 = loadConfig(rawConfig);
|
|
20499
20512
|
if (!config3) {
|
|
20500
20513
|
return formatError2(ErrorMessages.configurationMissing("SonarQube configuration not found.", [
|
|
20501
20514
|
"Set environment variables: SONAR_HOST_URL, SONAR_USER, and SONAR_PASSWORD",
|
|
@@ -20568,7 +20581,7 @@ ${setupResult.message}`);
|
|
|
20568
20581
|
}
|
|
20569
20582
|
|
|
20570
20583
|
// src/utils/shared-state.ts
|
|
20571
|
-
import { readFileSync, writeFileSync } from "node:fs";
|
|
20584
|
+
import { readFileSync, writeFileSync, renameSync } from "node:fs";
|
|
20572
20585
|
var SHARED_STATE_FILE = "/tmp/sonarqube-plugin-shared-state.json";
|
|
20573
20586
|
var readSharedState = () => {
|
|
20574
20587
|
try {
|
|
@@ -20581,7 +20594,9 @@ var readSharedState = () => {
|
|
|
20581
20594
|
var writeSharedState = (state) => {
|
|
20582
20595
|
try {
|
|
20583
20596
|
state.lastUpdated = new Date().toISOString();
|
|
20584
|
-
|
|
20597
|
+
const tmpFile = `${SHARED_STATE_FILE}.tmp.${process.pid}`;
|
|
20598
|
+
writeFileSync(tmpFile, JSON.stringify(state, null, 2));
|
|
20599
|
+
renameSync(tmpFile, SHARED_STATE_FILE);
|
|
20585
20600
|
} catch {}
|
|
20586
20601
|
};
|
|
20587
20602
|
var mapSessionToDirectory = (sessionId, directory) => {
|
|
@@ -20843,6 +20858,10 @@ var SonarQubePlugin = async ({ client, directory, worktree }) => {
|
|
|
20843
20858
|
safeLog("client.app.log failed (non-fatal)");
|
|
20844
20859
|
}
|
|
20845
20860
|
let pluginConfig;
|
|
20861
|
+
let pluginConfigLoadedAt = 0;
|
|
20862
|
+
const CONFIG_RELOAD_INTERVAL_MS = 60000;
|
|
20863
|
+
const transformCacheMap = new Map;
|
|
20864
|
+
const TRANSFORM_CACHE_TTL_MS = 60000;
|
|
20846
20865
|
let lastAnalysisResult;
|
|
20847
20866
|
const getConfig = () => pluginConfig;
|
|
20848
20867
|
const getDirectory = () => {
|
|
@@ -20853,8 +20872,9 @@ var SonarQubePlugin = async ({ client, directory, worktree }) => {
|
|
|
20853
20872
|
return effectiveDirectory;
|
|
20854
20873
|
};
|
|
20855
20874
|
const loadPluginConfig = async () => {
|
|
20856
|
-
if (pluginConfig)
|
|
20875
|
+
if (pluginConfig && Date.now() - pluginConfigLoadedAt < CONFIG_RELOAD_INTERVAL_MS)
|
|
20857
20876
|
return;
|
|
20877
|
+
pluginConfig = undefined;
|
|
20858
20878
|
const dir = getDirectory();
|
|
20859
20879
|
const sonarConfigPath = `${dir}/.sonarqube/config.json`;
|
|
20860
20880
|
try {
|
|
@@ -20862,16 +20882,18 @@ var SonarQubePlugin = async ({ client, directory, worktree }) => {
|
|
|
20862
20882
|
if (await configFile.exists()) {
|
|
20863
20883
|
const config3 = await configFile.json();
|
|
20864
20884
|
pluginConfig = { sonarqube: config3 };
|
|
20885
|
+
pluginConfigLoadedAt = Date.now();
|
|
20865
20886
|
safeLog(`Config loaded from ${sonarConfigPath}`);
|
|
20866
20887
|
return;
|
|
20867
20888
|
}
|
|
20868
20889
|
} catch {}
|
|
20869
20890
|
pluginConfig = {};
|
|
20891
|
+
pluginConfigLoadedAt = Date.now();
|
|
20870
20892
|
safeLog("Using environment variables for config");
|
|
20871
20893
|
};
|
|
20872
20894
|
const hooks = createHooks(getConfig, getDirectory);
|
|
20873
20895
|
let currentSessionId;
|
|
20874
|
-
|
|
20896
|
+
const initialCheckSessions = new Set;
|
|
20875
20897
|
const buildQualityNotification = (qgStatus, counts, qgFailed) => {
|
|
20876
20898
|
const statusEmoji = qgFailed ? "[FAIL]" : "[WARN]";
|
|
20877
20899
|
const blockerNote = counts.blocker > 0 ? `**Action Required:** There are BLOCKER issues that should be fixed.
|
|
@@ -20884,9 +20906,9 @@ var SonarQubePlugin = async ({ client, directory, worktree }) => {
|
|
|
20884
20906
|
${blockerNote}Use \`sonarqube({ action: "issues" })\` to see details or \`sonarqube({ action: "analyze" })\` to re-analyze.`;
|
|
20885
20907
|
};
|
|
20886
20908
|
const performInitialQualityCheck = async (sessionId) => {
|
|
20887
|
-
if (
|
|
20909
|
+
if (initialCheckSessions.has(sessionId))
|
|
20888
20910
|
return;
|
|
20889
|
-
|
|
20911
|
+
initialCheckSessions.add(sessionId);
|
|
20890
20912
|
try {
|
|
20891
20913
|
await loadPluginConfig();
|
|
20892
20914
|
const sonarConfig = pluginConfig?.["sonarqube"];
|
|
@@ -20933,7 +20955,7 @@ ${blockerNote}Use \`sonarqube({ action: "issues" })\` to see details or \`sonarq
|
|
|
20933
20955
|
});
|
|
20934
20956
|
} catch {}
|
|
20935
20957
|
};
|
|
20936
|
-
const qualityGatePattern = /Quality Gate
|
|
20958
|
+
const qualityGatePattern = /Quality Gate[:\s*]*\[(?:PASS|FAIL)\]\s*(\w+)|\*\*Quality Gate:\s*(\w+)\*\*/;
|
|
20937
20959
|
const issueCountPattern = /Blockers: (\d+), Critical: (\d+), Major: (\d+), Minor: (\d+), Info: (\d+)/;
|
|
20938
20960
|
const parseAnalysisResult = (message) => {
|
|
20939
20961
|
const resultMatch = qualityGatePattern.exec(message);
|
|
@@ -20942,7 +20964,7 @@ ${blockerNote}Use \`sonarqube({ action: "issues" })\` to see details or \`sonarq
|
|
|
20942
20964
|
return;
|
|
20943
20965
|
}
|
|
20944
20966
|
return {
|
|
20945
|
-
qualityGate: resultMatch[2],
|
|
20967
|
+
qualityGate: resultMatch[1] || resultMatch[2],
|
|
20946
20968
|
issues: {
|
|
20947
20969
|
blocker: Number.parseInt(issueMatch[1], 10),
|
|
20948
20970
|
critical: Number.parseInt(issueMatch[2], 10),
|
|
@@ -20958,10 +20980,11 @@ ${blockerNote}Use \`sonarqube({ action: "issues" })\` to see details or \`sonarq
|
|
|
20958
20980
|
return;
|
|
20959
20981
|
}
|
|
20960
20982
|
const payload = event.properties;
|
|
20961
|
-
|
|
20962
|
-
|
|
20983
|
+
const sessionId = payload?.info?.id;
|
|
20984
|
+
if (sessionId) {
|
|
20985
|
+
currentSessionId = sessionId;
|
|
20963
20986
|
if (event.type === "session.created") {
|
|
20964
|
-
mapSessionToDirectory(
|
|
20987
|
+
mapSessionToDirectory(sessionId, effectiveDirectory);
|
|
20965
20988
|
}
|
|
20966
20989
|
}
|
|
20967
20990
|
};
|
|
@@ -20970,8 +20993,8 @@ ${blockerNote}Use \`sonarqube({ action: "issues" })\` to see details or \`sonarq
|
|
|
20970
20993
|
return;
|
|
20971
20994
|
}
|
|
20972
20995
|
const payload = event.properties;
|
|
20973
|
-
if (payload?.
|
|
20974
|
-
hooks.fileEdited({ filePath: payload.
|
|
20996
|
+
if (payload?.file && !shouldIgnoreFile2(payload.file)) {
|
|
20997
|
+
hooks.fileEdited({ filePath: payload.file });
|
|
20975
20998
|
}
|
|
20976
20999
|
};
|
|
20977
21000
|
const injectAnalysisResults = async (message, _config, sessionId) => {
|
|
@@ -21001,8 +21024,8 @@ ${blockerNote}Use \`sonarqube({ action: "issues" })\` to see details or \`sonarq
|
|
|
21001
21024
|
if (!config3 || config3.level === "off" || !config3.autoAnalyze) {
|
|
21002
21025
|
return;
|
|
21003
21026
|
}
|
|
21004
|
-
const
|
|
21005
|
-
if (
|
|
21027
|
+
const editedFiles = hooks.getEditedFiles?.() ?? getEditedFiles();
|
|
21028
|
+
if (editedFiles.length === 0) {
|
|
21006
21029
|
return;
|
|
21007
21030
|
}
|
|
21008
21031
|
const message = await hooks.sessionIdle();
|
|
@@ -21013,7 +21036,7 @@ ${blockerNote}Use \`sonarqube({ action: "issues" })\` to see details or \`sonarq
|
|
|
21013
21036
|
if (parsedResult) {
|
|
21014
21037
|
lastAnalysisResult = parsedResult;
|
|
21015
21038
|
}
|
|
21016
|
-
const passed = message.includes("[PASS]");
|
|
21039
|
+
const passed = message.includes("[PASS]") || message.includes("Quality Gate") && message.includes("OK");
|
|
21017
21040
|
await showToast(passed ? "SonarQube: Quality Gate Passed" : "SonarQube: Issues Found", passed ? "success" : "error");
|
|
21018
21041
|
await injectAnalysisResults(message, config3, currentSessionId);
|
|
21019
21042
|
};
|
|
@@ -21112,7 +21135,7 @@ Git operation completed with changes. Consider running:
|
|
|
21112
21135
|
const handleGitPush = async (command, outputData) => {
|
|
21113
21136
|
if (!/git\s+push\b/.test(command))
|
|
21114
21137
|
return;
|
|
21115
|
-
if (outputData?.includes("error") || outputData?.includes("rejected"))
|
|
21138
|
+
if (outputData?.includes("error:") || outputData?.includes("fatal:") || outputData?.includes("rejected"))
|
|
21116
21139
|
return;
|
|
21117
21140
|
await showToast("Code pushed - SonarQube will analyze on server", "info");
|
|
21118
21141
|
};
|
|
@@ -21171,16 +21194,27 @@ Git operation completed with changes. Consider running:
|
|
|
21171
21194
|
safeLog(` effectiveDirectory (fallback): "${effectiveDirectory}"`);
|
|
21172
21195
|
const dir = sessionDir || effectiveDirectory;
|
|
21173
21196
|
safeLog(` FINAL dir used: "${dir}"`);
|
|
21197
|
+
const now = Date.now();
|
|
21198
|
+
const cachedEntry = transformCacheMap.get(dir);
|
|
21199
|
+
if (cachedEntry && now - cachedEntry.timestamp < TRANSFORM_CACHE_TTL_MS) {
|
|
21200
|
+
if (cachedEntry.data) {
|
|
21201
|
+
output.system.push(cachedEntry.data);
|
|
21202
|
+
}
|
|
21203
|
+
return;
|
|
21204
|
+
}
|
|
21174
21205
|
await loadPluginConfig();
|
|
21175
21206
|
const sonarConfig = pluginConfig?.["sonarqube"];
|
|
21176
21207
|
const config3 = loadConfig(sonarConfig);
|
|
21177
21208
|
if (!config3 || config3.level === "off") {
|
|
21178
21209
|
safeLog(` config level is off or null, returning early`);
|
|
21210
|
+
transformCacheMap.set(dir, { data: undefined, timestamp: now });
|
|
21179
21211
|
return;
|
|
21180
21212
|
}
|
|
21181
21213
|
const state = await getProjectState(dir);
|
|
21182
|
-
if (!state?.projectKey)
|
|
21214
|
+
if (!state?.projectKey) {
|
|
21215
|
+
transformCacheMap.set(dir, { data: undefined, timestamp: now });
|
|
21183
21216
|
return;
|
|
21217
|
+
}
|
|
21184
21218
|
const api2 = createSonarQubeAPI(config3, state);
|
|
21185
21219
|
const [qgStatus, counts, newCodeResponse] = await Promise.all([
|
|
21186
21220
|
api2.qualityGate.getStatus(state.projectKey),
|
|
@@ -21196,6 +21230,7 @@ Git operation completed with changes. Consider running:
|
|
|
21196
21230
|
const qgFailed = qgStatus.projectStatus.status !== "OK";
|
|
21197
21231
|
const newCodeIssues = newCodeResponse.paging.total;
|
|
21198
21232
|
if (!hasIssues && !qgFailed && newCodeIssues === 0) {
|
|
21233
|
+
transformCacheMap.set(dir, { data: undefined, timestamp: now });
|
|
21199
21234
|
return;
|
|
21200
21235
|
}
|
|
21201
21236
|
const systemContext = `## SonarQube Code Quality Status
|
|
@@ -21212,6 +21247,7 @@ ${config3.level === "enterprise" ? `This project follows enterprise-level qualit
|
|
|
21212
21247
|
- \`sonarqube({ action: "newissues" })\` - See issues in your recent changes (Clean as You Code)
|
|
21213
21248
|
- \`sonarqube({ action: "worstfiles" })\` - Find files needing most attention
|
|
21214
21249
|
- \`sonarqube({ action: "issues" })\` - See all issues`;
|
|
21250
|
+
transformCacheMap.set(dir, { data: systemContext, timestamp: now });
|
|
21215
21251
|
output.system.push(systemContext);
|
|
21216
21252
|
}, "experimental.chat.system.transform"),
|
|
21217
21253
|
tool: {
|
|
@@ -21270,6 +21306,7 @@ Example usage:
|
|
|
21270
21306
|
if (parsedResult) {
|
|
21271
21307
|
lastAnalysisResult = parsedResult;
|
|
21272
21308
|
}
|
|
21309
|
+
transformCacheMap.clear();
|
|
21273
21310
|
}
|
|
21274
21311
|
return result;
|
|
21275
21312
|
}
|