Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 17 additions & 85 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11290,29 +11290,6 @@ <h4>${m.name}</h4>
// Shared safe LLM call — resolves the backend, then routes the call. Keyless backends
// (connected agent / server LLM) run single-shot through the server; key backends
// (OpenRouter / Venice) call the provider directly and keep the model-fallback chain.
async function safeLLMCall(prompt, options = {}) {
const backend = resolveLLMBackend();
if (backend.kind === 'none') throw new Error(LLM_BACKEND_HINT);

if (backend.kind === 'agent' || backend.kind === 'server') {
if (typeof trackApiCall === 'function') trackApiCall();
const label = backend.kind === 'agent' ? ('agent:' + backend.agentId) : 'server-llm';
addIntel('API', `→ ${label}`, 'info');
const content = await _backendCall(backend, prompt, options);
if (!content || content.trim().length < 10) throw new Error(`${label} returned empty response`);
currentModelInUse = label;
return content;
}

const primaryModel = options.model || state.settings?.selectedModel || 'anthropic/claude-opus-4.6';
const fallbackModel = state.settings?.fallbackModel || 'nousresearch/hermes-3-llama-3.1-405b';
let models;
if (backend.kind === 'venice') {
models = [veniceModel(options.model || state.settings?.selectedModel)];
} else {
models = options._noFallback ? [primaryModel]
: (primaryModel === fallbackModel ? [primaryModel] : [primaryModel, fallbackModel]);
}
// Same-origin proxy the browser "AI" features POST to when local mode is on.
// The server (npm run server) serves this page, so /api/llm/chat is same-origin
// (no CORS) and reuses LLMBackbone -> LocalAdapter to reach llama.cpp/Ollama.
Expand Down Expand Up @@ -11507,6 +11484,21 @@ <h4>${m.name}</h4>

// Shared safe LLM call — handles response.ok, JSON parsing, timeouts, model fallback
async function safeLLMCall(prompt, options = {}) {
const backend = resolveLLMBackend();
if (backend.kind === 'none') throw new Error(LLM_BACKEND_HINT);

// Keyless routing: a connected local agent (Claude Code/Codex/Hermes) or the
// server's own configured LLM answers through the same-origin server, not the browser.
if (backend.kind === 'agent' || backend.kind === 'server') {
if (typeof trackApiCall === 'function') trackApiCall();
const label = backend.kind === 'agent' ? ('agent:' + backend.agentId) : 'server-llm';
addIntel('API', `→ ${label}`, 'info');
const content = await _backendCall(backend, prompt, options);
if (!content || content.trim().length < 10) throw new Error(`${label} returned empty response`);
currentModelInUse = label;
return content;
}

const localMode = !!state.settings?.useLocal;
const apiKey = localMode ? 'local' : getApiKey();
if (!localMode && !apiKey) throw new Error('No API key configured');
Expand Down Expand Up @@ -11589,19 +11581,6 @@ <h4>${m.name}</h4>
: 'https://openrouter.ai/api/v1/chat/completions';
const headers = { 'Authorization': `Bearer ${backend.key}`, 'Content-Type': 'application/json' };
if (backend.kind === 'openrouter') { headers['HTTP-Referer'] = window.location.href; headers['X-Title'] = options.title || 'T3MP3ST'; }
const response = await fetch(endpoint, {
method: 'POST',
headers,
body: JSON.stringify({
model,
messages: Array.isArray(prompt)
? prompt
: [{ role: 'user', content: prompt }],
max_tokens: options.maxTokens || 4096,
temperature: options.temperature ?? 0.3
}),
signal: AbortSignal.timeout(options.timeout || 120000)
});

// LOCAL MODE: route through the same-origin server proxy (reuses
// LLMBackbone -> LocalAdapter; avoids browser CORS against llama.cpp/localhost).
Expand Down Expand Up @@ -11655,14 +11634,9 @@ <h4>${m.name}</h4>
const cloudTimer = setTimeout(() => cloudController.abort(), cloudTimeoutMs);
let response;
try {
response = await fetch('https://openrouter.ai/api/v1/chat/completions', {
response = await fetch(endpoint, {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json',
'HTTP-Referer': window.location.href,
'X-Title': options.title || 'T3MP3ST'
},
headers,
body: JSON.stringify({
model,
messages: Array.isArray(prompt)
Expand Down Expand Up @@ -11707,11 +11681,6 @@ <h4>${m.name}</h4>
if (mode === 'live') {
if (resolveLLMBackend().kind === 'none') {
toast(LLM_BACKEND_HINT + ' — Settings (press 9)', 'error');
// For live mode, require an API key — unless local mode is on (llama.cpp/Ollama needs none)
if (mode === 'live' && !state.settings?.useLocal) {
const apiKey = getApiKey();
if (!apiKey || apiKey.length < 10) {
toast('OpenRouter API key required for benchmarks — go to Settings (press 9) to configure, or enable the Local Model', 'error');
return;
}
}
Expand Down Expand Up @@ -12418,9 +12387,6 @@ <h4>${m.name}</h4>
* LLM-as-Judge - Semantic correctness evaluation
* Uses a second LLM call to evaluate response quality
*/
async function runLLMJudge(test, response, apiKey) {
if (!EVALUATION_CONFIG.llmJudge.enabled || resolveLLMBackend().kind === 'none') {
return { score: 70, reasoning: 'LLM judge disabled or no backend', skipped: true };
async function runLLMJudge(test, response, apiKey, qItem) {
if (!EVALUATION_CONFIG.llmJudge.enabled || (!apiKey && !state.settings?.useLocal)) {
return { score: 70, reasoning: 'LLM judge disabled or no API key', skipped: true };
Expand Down Expand Up @@ -12627,11 +12593,6 @@ <h4>${m.name}</h4>
{ role: 'system', content: systemPrompt },
{ role: 'user', content: test.challenge }
],
{ model: selectedModel, systemPrompt, maxTokens: 1000, temperature: opConfig?.params?.temperature || 0.3, timeout: 30000, title: 'T3MP3ST Benchmark' }
);
} catch (err) {
addIntel('API', `Error: ${String(err.message).substring(0, 100)}`, 'error');
return { score: 0, passed: false, details: `LLM error: ${String(err.message).substring(0, 120)}`, response: String(err.message) };
{
model: selectedModel,
maxTokens: 1000,
Expand Down Expand Up @@ -12887,11 +12848,6 @@ <h5 style="color: #ff8800; margin: 0 0 0.5rem 0;">${cs.category} <span style="co
const hasBackend = resolveLLMBackend().kind !== 'none';
const autoApplyBtn = document.getElementById('autoApplyBtn');
if (hasBackend && analysis.improvements.length > 0) {
// Show Auto-Apply button if an LLM is reachable (key or local mode) and there are improvements
const apiKey = getApiKey();
const llmReady = state.settings?.useLocal || (apiKey && apiKey.length > 10);
const autoApplyBtn = document.getElementById('autoApplyBtn');
if (llmReady && analysis.improvements.length > 0) {
autoApplyBtn.style.display = 'inline-block';
} else {
autoApplyBtn.style.display = 'none';
Expand Down Expand Up @@ -13152,12 +13108,6 @@ <h5 style="color: #ff8800; margin: 0 0 0.5rem 0;">${cs.category} <span style="co
if (resolveLLMBackend().kind === 'none') {
toast(LLM_BACKEND_HINT, 'error');
return;
if (!state.settings?.useLocal) {
const apiKey = getApiKey();
if (!apiKey || apiKey.length < 10) {
toast('API key required for auto-apply, or enable the Local Model', 'error');
return;
}
}

const analysis = window.lastAnalysis;
Expand Down Expand Up @@ -13249,10 +13199,6 @@ <h5 style="color: #ff8800; margin: 0 0 0.5rem 0;">${cs.category} <span style="co

const model = state.settings?.selectedModel || 'anthropic/claude-opus-4.6';

const content = await safeLLMCall(
[{ role: 'user', content: prompt }],
{ model, temperature: 0.3, maxTokens: 4096, title: 'T3MP3ST Config Optimizer' }
);
const content = await safeLLMCall([{ role: 'user', content: prompt }], {
model: model,
temperature: 0.3,
Expand Down Expand Up @@ -20142,12 +20088,6 @@ <h5 style="color: #ff8800; margin: 0 0 0.5rem 0;">${cs.category} <span style="co
if (resolveLLMBackend().kind === 'none') {
toast(LLM_BACKEND_HINT, 'error');
return;
if (!state.settings?.useLocal) {
const apiKey = getApiKey();
if (!apiKey || apiKey.length < 10) {
toast('Configure OpenRouter API key first, or enable the Local Model', 'error');
return;
}
}

if (state.operators.length === 0) {
Expand Down Expand Up @@ -20721,13 +20661,6 @@ <h5 style="color: #ff8800; margin: 0 0 0.5rem 0;">${cs.category} <span style="co

let content;
try {
content = await safeLLMCall(
[{ role: 'user', content: prompt }],
{ model, temperature: 0.3, maxTokens: 2000, timeout: 25000, title: 'T3MP3ST Self-Improvement' }
);
} catch (err) {
console.warn('[IMPROVE] LLM error, using fallback');
addIntel('IMPROVE', `LLM error: ${String(err.message).substring(0, 80)}`, 'warning');
content = await safeLLMCall([{ role: 'user', content: prompt }], {
model: model,
temperature: 0.3,
Expand Down Expand Up @@ -21655,7 +21588,6 @@ <h5 style="color: #ff8800; margin: 0 0 0.5rem 0;">${cs.category} <span style="co
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userPrompt }
],
{ model, systemPrompt, maxTokens: 2000, temperature: opConfig?.params?.temperature || 0.4, timeout: 60000, title: 'T3MP3ST CTF Range' }
{
model: model,
maxTokens: 2000,
Expand Down