icoa-cli 2.19.77 → 2.19.78
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/lib/gemini.js +46 -10
- package/package.json +1 -1
package/dist/lib/gemini.js
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
import { GoogleGenAI } from '@google/genai';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
3
6
|
import { getConfig, saveConfig } from './config.js';
|
|
7
|
+
import { getRealExamState } from './exam-state.js';
|
|
8
|
+
const __dirname_gemini = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
let _cachedVersion = null;
|
|
10
|
+
function getCliVersion() {
|
|
11
|
+
if (_cachedVersion)
|
|
12
|
+
return _cachedVersion;
|
|
13
|
+
try {
|
|
14
|
+
const pkg = JSON.parse(readFileSync(join(__dirname_gemini, '..', '..', 'package.json'), 'utf-8'));
|
|
15
|
+
_cachedVersion = pkg.version || 'unknown';
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
_cachedVersion = 'unknown';
|
|
19
|
+
}
|
|
20
|
+
return _cachedVersion;
|
|
21
|
+
}
|
|
4
22
|
const SYSTEM_PROMPTS = {
|
|
5
23
|
A: `You are an AI assistant in a cybersecurity CTF competition called ICOA.
|
|
6
24
|
You are providing Level A (General Guidance) to a competitor.
|
|
@@ -170,24 +188,42 @@ export async function createChatSession(context, customSystemPrompt) {
|
|
|
170
188
|
return {
|
|
171
189
|
async sendMessage(msg) {
|
|
172
190
|
messages.push({ role: 'user', text: msg });
|
|
191
|
+
// Attach exam token if contestant is in a real exam — grants full
|
|
192
|
+
// 2048 maxTokens and higher rate limit. Demo/anonymous users rely on
|
|
193
|
+
// the User-Agent gate on the server side.
|
|
194
|
+
const realExam = getRealExamState();
|
|
195
|
+
const payload = {
|
|
196
|
+
systemPrompt,
|
|
197
|
+
messages,
|
|
198
|
+
model: modelName,
|
|
199
|
+
maxTokens: 2048,
|
|
200
|
+
deviceFingerprint: fp,
|
|
201
|
+
};
|
|
202
|
+
if (realExam?.session?.token) {
|
|
203
|
+
payload.examToken = realExam.session.token;
|
|
204
|
+
}
|
|
173
205
|
const res = await fetch(`${serverUrl}/api/icoa/ai/chat`, {
|
|
174
206
|
method: 'POST',
|
|
175
|
-
headers: {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
maxTokens: 2048,
|
|
181
|
-
deviceFingerprint: fp,
|
|
182
|
-
}),
|
|
207
|
+
headers: {
|
|
208
|
+
'Content-Type': 'application/json',
|
|
209
|
+
'User-Agent': `icoa-cli/${getCliVersion()}`,
|
|
210
|
+
},
|
|
211
|
+
body: JSON.stringify(payload),
|
|
183
212
|
signal: AbortSignal.timeout(60_000),
|
|
184
213
|
});
|
|
185
214
|
if (!res.ok) {
|
|
186
215
|
const err = await res.json().catch(() => ({ message: 'AI proxy error' }));
|
|
216
|
+
const msg = err.message || `AI proxy returned ${res.status}`;
|
|
217
|
+
if (res.status === 401) {
|
|
218
|
+
throw new Error(chalk.yellow('⚠ ') + 'Exam token expired. Re-enter via `exam <token>`.');
|
|
219
|
+
}
|
|
220
|
+
if (res.status === 403) {
|
|
221
|
+
throw new Error(chalk.yellow('⚠ ') + msg);
|
|
222
|
+
}
|
|
187
223
|
if (res.status === 429) {
|
|
188
|
-
throw new Error(chalk.yellow('⏳ ') +
|
|
224
|
+
throw new Error(chalk.yellow('⏳ ') + msg);
|
|
189
225
|
}
|
|
190
|
-
throw new Error(
|
|
226
|
+
throw new Error(msg);
|
|
191
227
|
}
|
|
192
228
|
const json = await res.json();
|
|
193
229
|
const text = filterFlagPatterns(json.data?.text || '');
|