@use-lattice/litmus 0.121.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/LICENSE +19 -0
- package/dist/src/accounts-Bt1oJb1Z.cjs +219 -0
- package/dist/src/accounts-DjOU8Rm3.js +178 -0
- package/dist/src/agentic-utils-D03IiXQc.js +153 -0
- package/dist/src/agentic-utils-Dh7xaMQM.cjs +180 -0
- package/dist/src/agents-C6BIMlZa.js +231 -0
- package/dist/src/agents-DvIpNX1L.cjs +666 -0
- package/dist/src/agents-ZP0RP9vV.cjs +231 -0
- package/dist/src/agents-maJXdjbR.js +665 -0
- package/dist/src/aimlapi-BTbQjG2E.cjs +30 -0
- package/dist/src/aimlapi-CwMxqfXP.js +30 -0
- package/dist/src/audio-BBUdvsde.cjs +97 -0
- package/dist/src/audio-D5DPZ7I-.js +97 -0
- package/dist/src/base-BEysXrkq.cjs +222 -0
- package/dist/src/base-C451JQfq.js +193 -0
- package/dist/src/blobs-BY8MDmpo.js +230 -0
- package/dist/src/blobs-BgcNn97m.cjs +256 -0
- package/dist/src/cache-BBE_lsTA.cjs +4 -0
- package/dist/src/cache-BkrqU5Ba.js +237 -0
- package/dist/src/cache-DsCxFlsZ.cjs +297 -0
- package/dist/src/chat-CPJWDP6a.cjs +289 -0
- package/dist/src/chat-CXX3xzkk.cjs +811 -0
- package/dist/src/chat-CcDgZFJ4.js +787 -0
- package/dist/src/chat-Dz5ZeGO2.js +289 -0
- package/dist/src/chatkit-Dw0mKkML.cjs +1158 -0
- package/dist/src/chatkit-swAIVuea.js +1157 -0
- package/dist/src/chunk-DEq-mXcV.js +15 -0
- package/dist/src/claude-agent-sdk-BXZJtOg6.js +379 -0
- package/dist/src/claude-agent-sdk-CkfyjDoG.cjs +383 -0
- package/dist/src/cloudflare-ai-BzpJcqUH.js +161 -0
- package/dist/src/cloudflare-ai-Cmy_R1y2.cjs +161 -0
- package/dist/src/cloudflare-gateway-B9tVQKok.cjs +272 -0
- package/dist/src/cloudflare-gateway-DrD3ew3H.js +272 -0
- package/dist/src/codex-sdk-Dezj9Nwm.js +1056 -0
- package/dist/src/codex-sdk-Dl9D4k5B.cjs +1060 -0
- package/dist/src/cometapi-C-9YvCHC.js +54 -0
- package/dist/src/cometapi-DHgDKoO2.cjs +54 -0
- package/dist/src/completion-B8Ctyxpr.js +120 -0
- package/dist/src/completion-Cxrt08sj.cjs +131 -0
- package/dist/src/createHash-BwgE13yv.cjs +27 -0
- package/dist/src/createHash-DmPQkvBh.js +15 -0
- package/dist/src/docker-BiqcTwLv.js +80 -0
- package/dist/src/docker-C7tEJnP-.cjs +80 -0
- package/dist/src/esm-C62Zofr1.cjs +409 -0
- package/dist/src/esm-DMVc93eh.js +379 -0
- package/dist/src/evalResult-C3NJPQOo.cjs +301 -0
- package/dist/src/evalResult-C7JJAPBb.js +295 -0
- package/dist/src/evalResult-DoVTZZWI.cjs +2 -0
- package/dist/src/extractor-DnMD3fwt.cjs +391 -0
- package/dist/src/extractor-DtlL28vL.js +374 -0
- package/dist/src/fetch-BTxakTSg.cjs +1133 -0
- package/dist/src/fetch-DQckpUFz.js +928 -0
- package/dist/src/fileExtensions-DnqA1y9x.js +85 -0
- package/dist/src/fileExtensions-bYh77CN8.cjs +114 -0
- package/dist/src/genaiTracer-CyZrmaK0.cjs +268 -0
- package/dist/src/genaiTracer-D3fD9dNV.js +256 -0
- package/dist/src/graders-BNscxFrU.js +13644 -0
- package/dist/src/graders-D2oE9Msq.js +2 -0
- package/dist/src/graders-c0Ez_w-9.cjs +2 -0
- package/dist/src/graders-d0F2M3e9.cjs +14056 -0
- package/dist/src/image-0ZhE0VlR.cjs +280 -0
- package/dist/src/image-CWE1pdNv.js +257 -0
- package/dist/src/image-D9ZK6hwL.js +163 -0
- package/dist/src/image-DKZgZITg.cjs +163 -0
- package/dist/src/index.cjs +11366 -0
- package/dist/src/index.d.cts +19640 -0
- package/dist/src/index.d.ts +19641 -0
- package/dist/src/index.js +11306 -0
- package/dist/src/invariant-Ddh24eXh.js +25 -0
- package/dist/src/invariant-kfQ8Bu82.cjs +30 -0
- package/dist/src/knowledgeBase-BgPyGFUd.cjs +122 -0
- package/dist/src/knowledgeBase-DyHilYaP.js +122 -0
- package/dist/src/litellm-CyMeneHS.js +135 -0
- package/dist/src/litellm-DWDF73yF.cjs +135 -0
- package/dist/src/logger-C40ZGil9.js +717 -0
- package/dist/src/logger-DyfK9PBt.cjs +917 -0
- package/dist/src/luma-ray-BAU9X_ep.cjs +315 -0
- package/dist/src/luma-ray-nwVseBbv.js +313 -0
- package/dist/src/messages-B5ADWTTv.js +245 -0
- package/dist/src/messages-BCnZfqrS.cjs +257 -0
- package/dist/src/meteor-DLZZ3osF.cjs +134 -0
- package/dist/src/meteor-DUiCJRC-.js +134 -0
- package/dist/src/modelslab-00cveB8L.cjs +163 -0
- package/dist/src/modelslab-D9sCU_L7.js +163 -0
- package/dist/src/nova-reel-CTapvqYH.js +276 -0
- package/dist/src/nova-reel-DlWuuroF.cjs +278 -0
- package/dist/src/nova-sonic-5UPWfeMv.cjs +363 -0
- package/dist/src/nova-sonic-BhSwQNym.js +363 -0
- package/dist/src/openai-BWrJK9d8.cjs +52 -0
- package/dist/src/openai-DumO8WQn.js +47 -0
- package/dist/src/openclaw-B8brrjC_.cjs +577 -0
- package/dist/src/openclaw-Bkayww9q.js +571 -0
- package/dist/src/opencode-sdk-7xjoDNiM.cjs +562 -0
- package/dist/src/opencode-sdk-SGwAPxht.js +558 -0
- package/dist/src/otlpReceiver-CoAHfAN9.cjs +15 -0
- package/dist/src/otlpReceiver-oO3EQwI9.js +14 -0
- package/dist/src/providerRegistry-4yjhaEM8.js +45 -0
- package/dist/src/providerRegistry-DhV4rJIc.cjs +50 -0
- package/dist/src/providers-B5RJVG-7.cjs +33609 -0
- package/dist/src/providers-BdmZCLzV.js +33262 -0
- package/dist/src/providers-CxtRxn8e.js +2 -0
- package/dist/src/providers-DnQLNbx1.cjs +3 -0
- package/dist/src/pythonUtils-BD0druiM.cjs +275 -0
- package/dist/src/pythonUtils-IBhn5YGR.js +249 -0
- package/dist/src/quiverai-BDOwZBsM.cjs +213 -0
- package/dist/src/quiverai-D3JTF5lD.js +213 -0
- package/dist/src/responses-B2LCDCXZ.js +667 -0
- package/dist/src/responses-BvNm4Xv9.cjs +685 -0
- package/dist/src/rubyUtils-B0NwnfpY.cjs +245 -0
- package/dist/src/rubyUtils-BroxzZ7c.cjs +2 -0
- package/dist/src/rubyUtils-hqVw5UvJ.js +222 -0
- package/dist/src/sagemaker-Cno2V-Sx.js +689 -0
- package/dist/src/sagemaker-fV_KUgs5.cjs +691 -0
- package/dist/src/server-BOuAXb06.cjs +238 -0
- package/dist/src/server-CtI-EWzm.cjs +2 -0
- package/dist/src/server-Cy3DZymt.js +189 -0
- package/dist/src/slack-CP8xBePa.js +135 -0
- package/dist/src/slack-DSQ1yXVb.cjs +135 -0
- package/dist/src/store-BwDDaBjb.cjs +246 -0
- package/dist/src/store-DcbLC593.cjs +2 -0
- package/dist/src/store-IGpqMIkv.js +240 -0
- package/dist/src/tables-3Q2cL7So.cjs +373 -0
- package/dist/src/tables-Bi2fjr4W.js +288 -0
- package/dist/src/telemetry-Bg2WqF79.js +161 -0
- package/dist/src/telemetry-D0x6u5kX.cjs +166 -0
- package/dist/src/telemetry-DXNimrI0.cjs +2 -0
- package/dist/src/text-B_UCRPp2.js +22 -0
- package/dist/src/text-CW1cyrwj.cjs +33 -0
- package/dist/src/tokenUsageUtils-NYT-WKS6.js +138 -0
- package/dist/src/tokenUsageUtils-bVa1ga6f.cjs +173 -0
- package/dist/src/transcription-Cl_W16Pr.js +122 -0
- package/dist/src/transcription-yt1EecY8.cjs +124 -0
- package/dist/src/transform-BCtGrl_W.cjs +228 -0
- package/dist/src/transform-Bv6gG2MJ.cjs +1688 -0
- package/dist/src/transform-CY1wbpRy.js +1507 -0
- package/dist/src/transform-DU8rUL9P.cjs +2 -0
- package/dist/src/transform-yWaShiKr.js +216 -0
- package/dist/src/transformersAvailability-BGkzavwb.js +35 -0
- package/dist/src/transformersAvailability-DKoRtQLy.cjs +35 -0
- package/dist/src/types-5aqHpBwE.cjs +3769 -0
- package/dist/src/types-Bn6D9c4U.js +3300 -0
- package/dist/src/util-BkKlTkI2.js +293 -0
- package/dist/src/util-CTh0bfOm.cjs +1119 -0
- package/dist/src/util-D17oBwo7.cjs +328 -0
- package/dist/src/util-DsS_-v4p.js +613 -0
- package/dist/src/util-DuntT1Ga.js +951 -0
- package/dist/src/util-aWjdCYMI.cjs +667 -0
- package/dist/src/utils-CisQwpjA.js +94 -0
- package/dist/src/utils-yWamDvmz.cjs +123 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/drizzle/0000_lush_hellion.sql +36 -0
- package/drizzle/0001_wide_calypso.sql +3 -0
- package/drizzle/0002_tidy_juggernaut.sql +1 -0
- package/drizzle/0003_lively_naoko.sql +8 -0
- package/drizzle/0004_minor_peter_quill.sql +19 -0
- package/drizzle/0005_silky_millenium_guard.sql +2 -0
- package/drizzle/0006_harsh_caretaker.sql +42 -0
- package/drizzle/0007_cloudy_wong.sql +1 -0
- package/drizzle/0008_broad_boomer.sql +2 -0
- package/drizzle/0009_strong_marten_broadcloak.sql +19 -0
- package/drizzle/0010_needy_bishop.sql +11 -0
- package/drizzle/0011_moaning_millenium_guard.sql +1 -0
- package/drizzle/0012_late_marten_broadcloak.sql +2 -0
- package/drizzle/0013_previous_dormammu.sql +9 -0
- package/drizzle/0014_lazy_captain_universe.sql +2 -0
- package/drizzle/0015_zippy_wallop.sql +29 -0
- package/drizzle/0016_jazzy_zemo.sql +2 -0
- package/drizzle/0017_reflective_praxagora.sql +4 -0
- package/drizzle/0018_fat_vanisher.sql +22 -0
- package/drizzle/0019_new_clint_barton.sql +8 -0
- package/drizzle/0020_skinny_maverick.sql +1 -0
- package/drizzle/0021_mysterious_madelyne_pryor.sql +13 -0
- package/drizzle/0022_sleepy_ultimo.sql +25 -0
- package/drizzle/0023_wooden_mandrill.sql +2 -0
- package/drizzle/AGENTS.md +68 -0
- package/drizzle/CLAUDE.md +1 -0
- package/drizzle/meta/0000_snapshot.json +221 -0
- package/drizzle/meta/0001_snapshot.json +214 -0
- package/drizzle/meta/0002_snapshot.json +221 -0
- package/drizzle/meta/0005_snapshot.json +369 -0
- package/drizzle/meta/0006_snapshot.json +638 -0
- package/drizzle/meta/0007_snapshot.json +640 -0
- package/drizzle/meta/0008_snapshot.json +649 -0
- package/drizzle/meta/0009_snapshot.json +554 -0
- package/drizzle/meta/0010_snapshot.json +619 -0
- package/drizzle/meta/0011_snapshot.json +627 -0
- package/drizzle/meta/0012_snapshot.json +639 -0
- package/drizzle/meta/0013_snapshot.json +717 -0
- package/drizzle/meta/0014_snapshot.json +717 -0
- package/drizzle/meta/0015_snapshot.json +897 -0
- package/drizzle/meta/0016_snapshot.json +1031 -0
- package/drizzle/meta/0018_snapshot.json +1210 -0
- package/drizzle/meta/0019_snapshot.json +1165 -0
- package/drizzle/meta/0020_snapshot.json +1232 -0
- package/drizzle/meta/0021_snapshot.json +1311 -0
- package/drizzle/meta/0022_snapshot.json +1481 -0
- package/drizzle/meta/0023_snapshot.json +1496 -0
- package/drizzle/meta/_journal.json +174 -0
- package/package.json +240 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
const require_logger = require("./logger-DyfK9PBt.cjs");
|
|
2
|
+
const require_fetch = require("./fetch-BTxakTSg.cjs");
|
|
3
|
+
const require_accounts = require("./accounts-Bt1oJb1Z.cjs");
|
|
4
|
+
let readline = require("readline");
|
|
5
|
+
readline = require_logger.__toESM(readline);
|
|
6
|
+
//#region src/redteam/remoteGeneration.ts
|
|
7
|
+
/**
|
|
8
|
+
* Gets the remote generation API endpoint URL.
|
|
9
|
+
* Prioritizes: env var > cloud config > default endpoint.
|
|
10
|
+
* @returns The remote generation URL
|
|
11
|
+
*/
|
|
12
|
+
function getRemoteGenerationUrl() {
|
|
13
|
+
const envUrl = require_logger.getEnvString("PROMPTFOO_REMOTE_GENERATION_URL");
|
|
14
|
+
if (envUrl) return envUrl;
|
|
15
|
+
const cloudConfig = new require_fetch.CloudConfig();
|
|
16
|
+
if (cloudConfig.isEnabled()) return cloudConfig.getApiHost() + "/api/v1/task";
|
|
17
|
+
return "https://api.promptfoo.app/api/v1/task";
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Check if remote generation should never be used.
|
|
21
|
+
* Respects both the general and redteam-specific disable flags.
|
|
22
|
+
* @returns true if remote generation is disabled
|
|
23
|
+
*/
|
|
24
|
+
function neverGenerateRemote() {
|
|
25
|
+
if (require_logger.getEnvBool("PROMPTFOO_DISABLE_REMOTE_GENERATION")) return true;
|
|
26
|
+
return require_logger.getEnvBool("PROMPTFOO_DISABLE_REDTEAM_REMOTE_GENERATION");
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Check if remote generation should never be used for non-redteam features.
|
|
30
|
+
* This allows granular control: disable redteam remote generation while allowing
|
|
31
|
+
* regular SimulatedUser to use remote generation.
|
|
32
|
+
* @returns true if ALL remote generation is disabled
|
|
33
|
+
*/
|
|
34
|
+
function neverGenerateRemoteForRegularEvals() {
|
|
35
|
+
return require_logger.getEnvBool("PROMPTFOO_DISABLE_REMOTE_GENERATION");
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Builds a remote URL with a substituted pathname, honoring env vars / cloud config.
|
|
39
|
+
*/
|
|
40
|
+
function buildRemoteUrl(pathname, fallback) {
|
|
41
|
+
if (neverGenerateRemote()) return null;
|
|
42
|
+
const envUrl = require_logger.getEnvString("PROMPTFOO_REMOTE_GENERATION_URL");
|
|
43
|
+
if (envUrl) try {
|
|
44
|
+
const url = new URL(envUrl);
|
|
45
|
+
url.pathname = pathname;
|
|
46
|
+
return url.toString();
|
|
47
|
+
} catch {
|
|
48
|
+
return fallback;
|
|
49
|
+
}
|
|
50
|
+
const cloudConfig = new require_fetch.CloudConfig();
|
|
51
|
+
if (cloudConfig.isEnabled()) return `${cloudConfig.getApiHost()}${pathname}`;
|
|
52
|
+
return fallback;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Gets the URL for checking remote API health based on configuration.
|
|
56
|
+
* @returns The health check URL, or null if remote generation is disabled.
|
|
57
|
+
*/
|
|
58
|
+
function getRemoteHealthUrl() {
|
|
59
|
+
return buildRemoteUrl("/health", "https://api.promptfoo.app/health");
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Gets the URL for checking remote API version based on configuration.
|
|
63
|
+
* @returns The version check URL, or null if remote generation is disabled.
|
|
64
|
+
*/
|
|
65
|
+
function getRemoteVersionUrl() {
|
|
66
|
+
return buildRemoteUrl("/version", "https://api.promptfoo.app/version");
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Determines if remote generation should be used based on configuration.
|
|
70
|
+
* @returns true if remote generation should be used
|
|
71
|
+
*/
|
|
72
|
+
function shouldGenerateRemote() {
|
|
73
|
+
if (neverGenerateRemote()) return false;
|
|
74
|
+
if (require_accounts.isLoggedIntoCloud()) return true;
|
|
75
|
+
return !require_logger.getEnvString("OPENAI_API_KEY") || (require_logger.state.remote ?? false);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Gets the URL for unaligned model inference (harmful content generation).
|
|
79
|
+
* Prioritizes: env var > cloud config > default endpoint.
|
|
80
|
+
* @returns The unaligned inference URL
|
|
81
|
+
*/
|
|
82
|
+
function getRemoteGenerationUrlForUnaligned() {
|
|
83
|
+
const envUrl = require_logger.getEnvString("PROMPTFOO_UNALIGNED_INFERENCE_ENDPOINT");
|
|
84
|
+
if (envUrl) return envUrl;
|
|
85
|
+
const cloudConfig = new require_fetch.CloudConfig();
|
|
86
|
+
if (cloudConfig.isEnabled()) return cloudConfig.getApiHost() + "/api/v1/task/harmful";
|
|
87
|
+
return "https://api.promptfoo.app/api/v1/task/harmful";
|
|
88
|
+
}
|
|
89
|
+
//#endregion
|
|
90
|
+
//#region src/util/readline.ts
|
|
91
|
+
/**
|
|
92
|
+
* Factory function for creating readline interface.
|
|
93
|
+
* This abstraction makes it easier to mock in tests and prevents open handles.
|
|
94
|
+
*/
|
|
95
|
+
function createReadlineInterface() {
|
|
96
|
+
return readline.default.createInterface({
|
|
97
|
+
input: process.stdin,
|
|
98
|
+
output: process.stdout
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Prompts the user with a question and returns their answer.
|
|
103
|
+
* Automatically handles cleanup of the readline interface.
|
|
104
|
+
*/
|
|
105
|
+
async function promptUser(question) {
|
|
106
|
+
return new Promise((resolve, reject) => {
|
|
107
|
+
let rl = null;
|
|
108
|
+
try {
|
|
109
|
+
rl = createReadlineInterface();
|
|
110
|
+
rl.on("error", (err) => {
|
|
111
|
+
if (rl) rl.close();
|
|
112
|
+
reject(err);
|
|
113
|
+
});
|
|
114
|
+
rl.question(question, (answer) => {
|
|
115
|
+
if (rl) rl.close();
|
|
116
|
+
resolve(answer);
|
|
117
|
+
});
|
|
118
|
+
} catch (err) {
|
|
119
|
+
if (rl) rl.close();
|
|
120
|
+
reject(err);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Prompts the user with a yes/no question and returns a boolean.
|
|
126
|
+
* @param question The question to ask
|
|
127
|
+
* @param defaultYes If true, empty response defaults to yes. If false, defaults to no.
|
|
128
|
+
*/
|
|
129
|
+
async function promptYesNo(question, defaultYes = false) {
|
|
130
|
+
const answer = await promptUser(`${question} ${defaultYes ? "(Y/n): " : "(y/N): "}`);
|
|
131
|
+
if (defaultYes) return !answer.trim().toLowerCase().startsWith("n");
|
|
132
|
+
return answer.trim().toLowerCase().startsWith("y");
|
|
133
|
+
}
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src/util/server.ts
|
|
136
|
+
const BrowserBehavior = {
|
|
137
|
+
ASK: 0,
|
|
138
|
+
OPEN: 1,
|
|
139
|
+
SKIP: 2,
|
|
140
|
+
OPEN_TO_REPORT: 3,
|
|
141
|
+
OPEN_TO_REDTEAM_CREATE: 4,
|
|
142
|
+
OPEN_TO_EVAL_SETUP: 5
|
|
143
|
+
};
|
|
144
|
+
BrowserBehavior.ASK, BrowserBehavior.OPEN, BrowserBehavior.SKIP, BrowserBehavior.OPEN_TO_REPORT, BrowserBehavior.OPEN_TO_REDTEAM_CREATE, BrowserBehavior.OPEN_TO_EVAL_SETUP;
|
|
145
|
+
const featureCache = /* @__PURE__ */ new Map();
|
|
146
|
+
/**
|
|
147
|
+
* Checks if a server supports a specific feature based on build date
|
|
148
|
+
* @param featureName - Name of the feature (for caching and logging)
|
|
149
|
+
* @param requiredBuildDate - Minimum build date when feature was added (ISO string)
|
|
150
|
+
* @returns Promise<boolean> - true if server supports the feature
|
|
151
|
+
*/
|
|
152
|
+
async function checkServerFeatureSupport(featureName, requiredBuildDate) {
|
|
153
|
+
const cacheKey = `${featureName}`;
|
|
154
|
+
if (featureCache.has(cacheKey)) return featureCache.get(cacheKey);
|
|
155
|
+
let supported = false;
|
|
156
|
+
try {
|
|
157
|
+
require_logger.logger.debug(`[Feature Detection] Checking server support for feature: ${featureName}`);
|
|
158
|
+
const versionUrl = getRemoteVersionUrl();
|
|
159
|
+
if (versionUrl) {
|
|
160
|
+
const data = await (await require_fetch.fetchWithProxy(versionUrl, {
|
|
161
|
+
method: "GET",
|
|
162
|
+
headers: { "Content-Type": "application/json" }
|
|
163
|
+
})).json();
|
|
164
|
+
if (data.buildDate) {
|
|
165
|
+
supported = new Date(data.buildDate) >= new Date(requiredBuildDate);
|
|
166
|
+
require_logger.logger.debug(`[Feature Detection] ${featureName}: buildDate=${data.buildDate}, required=${requiredBuildDate}, supported=${supported}`);
|
|
167
|
+
} else {
|
|
168
|
+
require_logger.logger.debug(`[Feature Detection] ${featureName}: no version info, assuming not supported`);
|
|
169
|
+
supported = false;
|
|
170
|
+
}
|
|
171
|
+
} else {
|
|
172
|
+
require_logger.logger.debug(`[Feature Detection] No remote URL available for ${featureName}, assuming local server supports it`);
|
|
173
|
+
supported = true;
|
|
174
|
+
}
|
|
175
|
+
} catch (error) {
|
|
176
|
+
require_logger.logger.debug(`[Feature Detection] Version check failed for ${featureName}, assuming not supported: ${error}`);
|
|
177
|
+
supported = false;
|
|
178
|
+
}
|
|
179
|
+
featureCache.set(cacheKey, supported);
|
|
180
|
+
return supported;
|
|
181
|
+
}
|
|
182
|
+
//#endregion
|
|
183
|
+
Object.defineProperty(exports, "BrowserBehavior", {
|
|
184
|
+
enumerable: true,
|
|
185
|
+
get: function() {
|
|
186
|
+
return BrowserBehavior;
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
Object.defineProperty(exports, "checkServerFeatureSupport", {
|
|
190
|
+
enumerable: true,
|
|
191
|
+
get: function() {
|
|
192
|
+
return checkServerFeatureSupport;
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
Object.defineProperty(exports, "getRemoteGenerationUrl", {
|
|
196
|
+
enumerable: true,
|
|
197
|
+
get: function() {
|
|
198
|
+
return getRemoteGenerationUrl;
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
Object.defineProperty(exports, "getRemoteGenerationUrlForUnaligned", {
|
|
202
|
+
enumerable: true,
|
|
203
|
+
get: function() {
|
|
204
|
+
return getRemoteGenerationUrlForUnaligned;
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
Object.defineProperty(exports, "getRemoteHealthUrl", {
|
|
208
|
+
enumerable: true,
|
|
209
|
+
get: function() {
|
|
210
|
+
return getRemoteHealthUrl;
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
Object.defineProperty(exports, "neverGenerateRemote", {
|
|
214
|
+
enumerable: true,
|
|
215
|
+
get: function() {
|
|
216
|
+
return neverGenerateRemote;
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
Object.defineProperty(exports, "neverGenerateRemoteForRegularEvals", {
|
|
220
|
+
enumerable: true,
|
|
221
|
+
get: function() {
|
|
222
|
+
return neverGenerateRemoteForRegularEvals;
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
Object.defineProperty(exports, "promptYesNo", {
|
|
226
|
+
enumerable: true,
|
|
227
|
+
get: function() {
|
|
228
|
+
return promptYesNo;
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
Object.defineProperty(exports, "shouldGenerateRemote", {
|
|
232
|
+
enumerable: true,
|
|
233
|
+
get: function() {
|
|
234
|
+
return shouldGenerateRemote;
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
//# sourceMappingURL=server-BOuAXb06.cjs.map
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-DEq-mXcV.js";
|
|
2
|
+
import { T as state, r as logger, v as getEnvBool, x as getEnvString } from "./logger-C40ZGil9.js";
|
|
3
|
+
import { a as CloudConfig, t as fetchWithProxy } from "./fetch-DQckpUFz.js";
|
|
4
|
+
import { o as isLoggedIntoCloud } from "./accounts-DjOU8Rm3.js";
|
|
5
|
+
import readline from "readline";
|
|
6
|
+
//#region src/redteam/remoteGeneration.ts
|
|
7
|
+
/**
|
|
8
|
+
* Gets the remote generation API endpoint URL.
|
|
9
|
+
* Prioritizes: env var > cloud config > default endpoint.
|
|
10
|
+
* @returns The remote generation URL
|
|
11
|
+
*/
|
|
12
|
+
function getRemoteGenerationUrl() {
|
|
13
|
+
const envUrl = getEnvString("PROMPTFOO_REMOTE_GENERATION_URL");
|
|
14
|
+
if (envUrl) return envUrl;
|
|
15
|
+
const cloudConfig = new CloudConfig();
|
|
16
|
+
if (cloudConfig.isEnabled()) return cloudConfig.getApiHost() + "/api/v1/task";
|
|
17
|
+
return "https://api.promptfoo.app/api/v1/task";
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Check if remote generation should never be used.
|
|
21
|
+
* Respects both the general and redteam-specific disable flags.
|
|
22
|
+
* @returns true if remote generation is disabled
|
|
23
|
+
*/
|
|
24
|
+
function neverGenerateRemote() {
|
|
25
|
+
if (getEnvBool("PROMPTFOO_DISABLE_REMOTE_GENERATION")) return true;
|
|
26
|
+
return getEnvBool("PROMPTFOO_DISABLE_REDTEAM_REMOTE_GENERATION");
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Check if remote generation should never be used for non-redteam features.
|
|
30
|
+
* This allows granular control: disable redteam remote generation while allowing
|
|
31
|
+
* regular SimulatedUser to use remote generation.
|
|
32
|
+
* @returns true if ALL remote generation is disabled
|
|
33
|
+
*/
|
|
34
|
+
function neverGenerateRemoteForRegularEvals() {
|
|
35
|
+
return getEnvBool("PROMPTFOO_DISABLE_REMOTE_GENERATION");
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Builds a remote URL with a substituted pathname, honoring env vars / cloud config.
|
|
39
|
+
*/
|
|
40
|
+
function buildRemoteUrl(pathname, fallback) {
|
|
41
|
+
if (neverGenerateRemote()) return null;
|
|
42
|
+
const envUrl = getEnvString("PROMPTFOO_REMOTE_GENERATION_URL");
|
|
43
|
+
if (envUrl) try {
|
|
44
|
+
const url = new URL(envUrl);
|
|
45
|
+
url.pathname = pathname;
|
|
46
|
+
return url.toString();
|
|
47
|
+
} catch {
|
|
48
|
+
return fallback;
|
|
49
|
+
}
|
|
50
|
+
const cloudConfig = new CloudConfig();
|
|
51
|
+
if (cloudConfig.isEnabled()) return `${cloudConfig.getApiHost()}${pathname}`;
|
|
52
|
+
return fallback;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Gets the URL for checking remote API health based on configuration.
|
|
56
|
+
* @returns The health check URL, or null if remote generation is disabled.
|
|
57
|
+
*/
|
|
58
|
+
function getRemoteHealthUrl() {
|
|
59
|
+
return buildRemoteUrl("/health", "https://api.promptfoo.app/health");
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Gets the URL for checking remote API version based on configuration.
|
|
63
|
+
* @returns The version check URL, or null if remote generation is disabled.
|
|
64
|
+
*/
|
|
65
|
+
function getRemoteVersionUrl() {
|
|
66
|
+
return buildRemoteUrl("/version", "https://api.promptfoo.app/version");
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Determines if remote generation should be used based on configuration.
|
|
70
|
+
* @returns true if remote generation should be used
|
|
71
|
+
*/
|
|
72
|
+
function shouldGenerateRemote() {
|
|
73
|
+
if (neverGenerateRemote()) return false;
|
|
74
|
+
if (isLoggedIntoCloud()) return true;
|
|
75
|
+
return !getEnvString("OPENAI_API_KEY") || (state.remote ?? false);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Gets the URL for unaligned model inference (harmful content generation).
|
|
79
|
+
* Prioritizes: env var > cloud config > default endpoint.
|
|
80
|
+
* @returns The unaligned inference URL
|
|
81
|
+
*/
|
|
82
|
+
function getRemoteGenerationUrlForUnaligned() {
|
|
83
|
+
const envUrl = getEnvString("PROMPTFOO_UNALIGNED_INFERENCE_ENDPOINT");
|
|
84
|
+
if (envUrl) return envUrl;
|
|
85
|
+
const cloudConfig = new CloudConfig();
|
|
86
|
+
if (cloudConfig.isEnabled()) return cloudConfig.getApiHost() + "/api/v1/task/harmful";
|
|
87
|
+
return "https://api.promptfoo.app/api/v1/task/harmful";
|
|
88
|
+
}
|
|
89
|
+
//#endregion
|
|
90
|
+
//#region src/util/readline.ts
|
|
91
|
+
/**
|
|
92
|
+
* Factory function for creating readline interface.
|
|
93
|
+
* This abstraction makes it easier to mock in tests and prevents open handles.
|
|
94
|
+
*/
|
|
95
|
+
function createReadlineInterface() {
|
|
96
|
+
return readline.createInterface({
|
|
97
|
+
input: process.stdin,
|
|
98
|
+
output: process.stdout
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Prompts the user with a question and returns their answer.
|
|
103
|
+
* Automatically handles cleanup of the readline interface.
|
|
104
|
+
*/
|
|
105
|
+
async function promptUser(question) {
|
|
106
|
+
return new Promise((resolve, reject) => {
|
|
107
|
+
let rl = null;
|
|
108
|
+
try {
|
|
109
|
+
rl = createReadlineInterface();
|
|
110
|
+
rl.on("error", (err) => {
|
|
111
|
+
if (rl) rl.close();
|
|
112
|
+
reject(err);
|
|
113
|
+
});
|
|
114
|
+
rl.question(question, (answer) => {
|
|
115
|
+
if (rl) rl.close();
|
|
116
|
+
resolve(answer);
|
|
117
|
+
});
|
|
118
|
+
} catch (err) {
|
|
119
|
+
if (rl) rl.close();
|
|
120
|
+
reject(err);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Prompts the user with a yes/no question and returns a boolean.
|
|
126
|
+
* @param question The question to ask
|
|
127
|
+
* @param defaultYes If true, empty response defaults to yes. If false, defaults to no.
|
|
128
|
+
*/
|
|
129
|
+
async function promptYesNo(question, defaultYes = false) {
|
|
130
|
+
const answer = await promptUser(`${question} ${defaultYes ? "(Y/n): " : "(y/N): "}`);
|
|
131
|
+
if (defaultYes) return !answer.trim().toLowerCase().startsWith("n");
|
|
132
|
+
return answer.trim().toLowerCase().startsWith("y");
|
|
133
|
+
}
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src/util/server.ts
|
|
136
|
+
var server_exports = /* @__PURE__ */ __exportAll({
|
|
137
|
+
BrowserBehavior: () => BrowserBehavior,
|
|
138
|
+
checkServerFeatureSupport: () => checkServerFeatureSupport
|
|
139
|
+
});
|
|
140
|
+
const BrowserBehavior = {
|
|
141
|
+
ASK: 0,
|
|
142
|
+
OPEN: 1,
|
|
143
|
+
SKIP: 2,
|
|
144
|
+
OPEN_TO_REPORT: 3,
|
|
145
|
+
OPEN_TO_REDTEAM_CREATE: 4,
|
|
146
|
+
OPEN_TO_EVAL_SETUP: 5
|
|
147
|
+
};
|
|
148
|
+
BrowserBehavior.ASK, BrowserBehavior.OPEN, BrowserBehavior.SKIP, BrowserBehavior.OPEN_TO_REPORT, BrowserBehavior.OPEN_TO_REDTEAM_CREATE, BrowserBehavior.OPEN_TO_EVAL_SETUP;
|
|
149
|
+
const featureCache = /* @__PURE__ */ new Map();
|
|
150
|
+
/**
|
|
151
|
+
* Checks if a server supports a specific feature based on build date
|
|
152
|
+
* @param featureName - Name of the feature (for caching and logging)
|
|
153
|
+
* @param requiredBuildDate - Minimum build date when feature was added (ISO string)
|
|
154
|
+
* @returns Promise<boolean> - true if server supports the feature
|
|
155
|
+
*/
|
|
156
|
+
async function checkServerFeatureSupport(featureName, requiredBuildDate) {
|
|
157
|
+
const cacheKey = `${featureName}`;
|
|
158
|
+
if (featureCache.has(cacheKey)) return featureCache.get(cacheKey);
|
|
159
|
+
let supported = false;
|
|
160
|
+
try {
|
|
161
|
+
logger.debug(`[Feature Detection] Checking server support for feature: ${featureName}`);
|
|
162
|
+
const versionUrl = getRemoteVersionUrl();
|
|
163
|
+
if (versionUrl) {
|
|
164
|
+
const data = await (await fetchWithProxy(versionUrl, {
|
|
165
|
+
method: "GET",
|
|
166
|
+
headers: { "Content-Type": "application/json" }
|
|
167
|
+
})).json();
|
|
168
|
+
if (data.buildDate) {
|
|
169
|
+
supported = new Date(data.buildDate) >= new Date(requiredBuildDate);
|
|
170
|
+
logger.debug(`[Feature Detection] ${featureName}: buildDate=${data.buildDate}, required=${requiredBuildDate}, supported=${supported}`);
|
|
171
|
+
} else {
|
|
172
|
+
logger.debug(`[Feature Detection] ${featureName}: no version info, assuming not supported`);
|
|
173
|
+
supported = false;
|
|
174
|
+
}
|
|
175
|
+
} else {
|
|
176
|
+
logger.debug(`[Feature Detection] No remote URL available for ${featureName}, assuming local server supports it`);
|
|
177
|
+
supported = true;
|
|
178
|
+
}
|
|
179
|
+
} catch (error) {
|
|
180
|
+
logger.debug(`[Feature Detection] Version check failed for ${featureName}, assuming not supported: ${error}`);
|
|
181
|
+
supported = false;
|
|
182
|
+
}
|
|
183
|
+
featureCache.set(cacheKey, supported);
|
|
184
|
+
return supported;
|
|
185
|
+
}
|
|
186
|
+
//#endregion
|
|
187
|
+
export { getRemoteGenerationUrlForUnaligned as a, neverGenerateRemoteForRegularEvals as c, getRemoteGenerationUrl as i, shouldGenerateRemote as l, server_exports as n, getRemoteHealthUrl as o, promptYesNo as r, neverGenerateRemote as s, checkServerFeatureSupport as t };
|
|
188
|
+
|
|
189
|
+
//# sourceMappingURL=server-Cy3DZymt.js.map
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { r as logger } from "./logger-C40ZGil9.js";
|
|
2
|
+
import { WebClient } from "@slack/web-api";
|
|
3
|
+
//#region src/providers/slack.ts
|
|
4
|
+
var SlackProvider = class {
|
|
5
|
+
client;
|
|
6
|
+
options;
|
|
7
|
+
constructor(options = {}) {
|
|
8
|
+
this.options = options;
|
|
9
|
+
const token = options.config?.token || process.env.SLACK_BOT_TOKEN;
|
|
10
|
+
if (!token) throw new Error("Slack provider requires a token. Set SLACK_BOT_TOKEN or provide it in config.");
|
|
11
|
+
if (!options.config?.channel) throw new Error("Slack provider requires a channel ID");
|
|
12
|
+
this.client = new WebClient(token);
|
|
13
|
+
}
|
|
14
|
+
id() {
|
|
15
|
+
return this.options.id || "slack";
|
|
16
|
+
}
|
|
17
|
+
async callApi(prompt, _context, _options) {
|
|
18
|
+
const config = this.options.config;
|
|
19
|
+
const channel = config.channel;
|
|
20
|
+
const timeout = config.timeout || 6e4;
|
|
21
|
+
const responseStrategy = config.responseStrategy || "first";
|
|
22
|
+
try {
|
|
23
|
+
const messageText = config.formatMessage ? config.formatMessage(prompt) : prompt;
|
|
24
|
+
const startTime = Date.now();
|
|
25
|
+
const postResult = await this.client.chat.postMessage({
|
|
26
|
+
channel,
|
|
27
|
+
text: messageText,
|
|
28
|
+
thread_ts: config.threadTs,
|
|
29
|
+
mrkdwn: true
|
|
30
|
+
});
|
|
31
|
+
if (!postResult.ok || !postResult.ts) throw new Error("Failed to post message to Slack");
|
|
32
|
+
const messageTs = postResult.ts;
|
|
33
|
+
let responseText;
|
|
34
|
+
const responseMetadata = {
|
|
35
|
+
messageTs,
|
|
36
|
+
channel
|
|
37
|
+
};
|
|
38
|
+
switch (responseStrategy) {
|
|
39
|
+
case "timeout":
|
|
40
|
+
responseText = await this.collectResponsesUntilTimeout(channel, messageTs, timeout);
|
|
41
|
+
break;
|
|
42
|
+
case "user":
|
|
43
|
+
if (!config.waitForUser) throw new Error("waitForUser must be specified when using \"user\" response strategy");
|
|
44
|
+
responseText = await this.waitForUserResponse(channel, messageTs, config.waitForUser, timeout);
|
|
45
|
+
responseMetadata.waitForUser = config.waitForUser;
|
|
46
|
+
break;
|
|
47
|
+
default:
|
|
48
|
+
responseText = await this.waitForFirstResponse(channel, messageTs, timeout);
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
if (config.includeThread) responseMetadata.threadTs = messageTs;
|
|
52
|
+
responseMetadata.responseTime = Date.now() - startTime;
|
|
53
|
+
return {
|
|
54
|
+
output: responseText,
|
|
55
|
+
metadata: responseMetadata
|
|
56
|
+
};
|
|
57
|
+
} catch (error) {
|
|
58
|
+
logger.error(`Slack provider error: ${error}`);
|
|
59
|
+
if (error?.data?.error) {
|
|
60
|
+
const slackError = error.data.error;
|
|
61
|
+
switch (slackError) {
|
|
62
|
+
case "channel_not_found": return { error: `Channel ${channel} not found. Please check the channel ID.` };
|
|
63
|
+
case "not_in_channel": return { error: `Bot is not in channel ${channel}. Please invite the bot first.` };
|
|
64
|
+
case "missing_scope": return { error: "Bot token is missing required scopes. Please check permissions." };
|
|
65
|
+
case "ratelimited": return { error: "Slack API rate limit exceeded. Please try again later." };
|
|
66
|
+
default: return { error: `Slack API error: ${slackError}` };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return { error: error instanceof Error ? error.message : "Unknown error" };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async waitForFirstResponse(channel, afterTs, timeout) {
|
|
73
|
+
const startTime = Date.now();
|
|
74
|
+
while (Date.now() - startTime < timeout) try {
|
|
75
|
+
const result = await this.client.conversations.history({
|
|
76
|
+
channel,
|
|
77
|
+
oldest: afterTs,
|
|
78
|
+
limit: 10
|
|
79
|
+
});
|
|
80
|
+
if (result.messages && result.messages.length > 0) {
|
|
81
|
+
const response = result.messages.filter((msg) => msg.ts !== afterTs && msg.type === "message" && !msg.bot_id).sort((a, b) => parseFloat(a.ts || "0") - parseFloat(b.ts || "0"))[0];
|
|
82
|
+
if (response && response.text) return response.text;
|
|
83
|
+
}
|
|
84
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
85
|
+
} catch (error) {
|
|
86
|
+
logger.error(`Error fetching Slack messages: ${error}`);
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
throw new Error(`Timeout waiting for Slack response after ${timeout}ms`);
|
|
90
|
+
}
|
|
91
|
+
async waitForUserResponse(channel, afterTs, userId, timeout) {
|
|
92
|
+
const startTime = Date.now();
|
|
93
|
+
while (Date.now() - startTime < timeout) try {
|
|
94
|
+
const result = await this.client.conversations.history({
|
|
95
|
+
channel,
|
|
96
|
+
oldest: afterTs,
|
|
97
|
+
limit: 20
|
|
98
|
+
});
|
|
99
|
+
if (result.messages && result.messages.length > 0) {
|
|
100
|
+
const response = result.messages.filter((msg) => msg.ts !== afterTs && msg.type === "message" && msg.user === userId).sort((a, b) => parseFloat(a.ts || "0") - parseFloat(b.ts || "0"))[0];
|
|
101
|
+
if (response && response.text) return response.text;
|
|
102
|
+
}
|
|
103
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
104
|
+
} catch (error) {
|
|
105
|
+
logger.error(`Error fetching Slack messages: ${error}`);
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
throw new Error(`Timeout waiting for response from user ${userId} after ${timeout}ms`);
|
|
109
|
+
}
|
|
110
|
+
async collectResponsesUntilTimeout(channel, afterTs, timeout) {
|
|
111
|
+
const startTime = Date.now();
|
|
112
|
+
const responses = [];
|
|
113
|
+
const seenTimestamps = new Set([afterTs]);
|
|
114
|
+
while (Date.now() - startTime < timeout) try {
|
|
115
|
+
const result = await this.client.conversations.history({
|
|
116
|
+
channel,
|
|
117
|
+
oldest: afterTs,
|
|
118
|
+
limit: 50
|
|
119
|
+
});
|
|
120
|
+
if (result.messages && result.messages.length > 0) result.messages.filter((msg) => !seenTimestamps.has(msg.ts || "") && msg.type === "message" && !msg.bot_id).sort((a, b) => parseFloat(a.ts || "0") - parseFloat(b.ts || "0")).forEach((msg) => {
|
|
121
|
+
if (msg.ts) seenTimestamps.add(msg.ts);
|
|
122
|
+
if (msg.text) responses.push(msg.text);
|
|
123
|
+
});
|
|
124
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
125
|
+
} catch (error) {
|
|
126
|
+
logger.error(`Error fetching Slack messages: ${error}`);
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
return responses.join("\n\n");
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
//#endregion
|
|
133
|
+
export { SlackProvider };
|
|
134
|
+
|
|
135
|
+
//# sourceMappingURL=slack-CP8xBePa.js.map
|