feat: add advanced context actions and optional translation
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
import { renderPrompt, ACTION_GROUPS } from './actions.js';
|
||||
import { normalizeLanguage } from './settings.js';
|
||||
import { serializePrompt, MAX_URL_CHARS } from './build-url.js';
|
||||
|
||||
const IDS = new Set([...Object.values(ACTION_GROUPS).flat(), 'translate']);
|
||||
const error = message => ({ kind: 'error', message });
|
||||
|
||||
export function prepareAction(request) {
|
||||
if (!IDS.has(request.actionId)) return error('This action is no longer available. Please try again.');
|
||||
const source = String(request.source ?? '').trim();
|
||||
if (!source && request.actionId !== 'ask') return error('There is no text or URL to send. Please select it again.');
|
||||
const isUrl = request.actionId.includes('-');
|
||||
if (isUrl) {
|
||||
try {
|
||||
const parsed = new URL(source);
|
||||
if (!['http:', 'https:'].includes(parsed.protocol) || parsed.username || parsed.password) throw new Error();
|
||||
} catch {
|
||||
return error('This action supports only HTTP or HTTPS links without embedded login credentials.');
|
||||
}
|
||||
}
|
||||
let language = normalizeLanguage(request.language);
|
||||
if (request.actionId === 'translate') {
|
||||
if (!language && request.settings.translationMode === 'preferred') language = normalizeLanguage(request.settings.translationLanguage);
|
||||
if (!language) return { kind: 'language' };
|
||||
}
|
||||
const resolved = { ...request, language };
|
||||
const serialize = text => serializePrompt(request.settings, renderPrompt(resolved, text));
|
||||
const url = serialize(source);
|
||||
if (url.length <= MAX_URL_CHARS) return { kind: 'ready', url };
|
||||
if (isUrl) return error('This URL is too long to send intact. No part of it has been sent.');
|
||||
const marker = '\n[Selected text shortened]';
|
||||
if (serialize(marker).length >= MAX_URL_CHARS) return error('The prompt instructions are too long. Shorten your prompt template and try again.');
|
||||
const points = Array.from(source);
|
||||
let low = 0, high = points.length;
|
||||
while (low < high) {
|
||||
const mid = Math.ceil((low + high) / 2);
|
||||
if (serialize(points.slice(0, mid).join('') + marker).length <= MAX_URL_CHARS) low = mid;
|
||||
else high = mid - 1;
|
||||
}
|
||||
let kept = points.slice(0, low).join('');
|
||||
const boundary = kept.search(/\s+\S*$/u);
|
||||
if (boundary > kept.length * 0.9) kept = kept.slice(0, boundary);
|
||||
if (!kept.trim()) return error('The prompt leaves no room for the selected text. Shorten the prompt template and try again.');
|
||||
return { kind: 'shortened', url: serialize(kept + marker) };
|
||||
}
|
||||
Reference in New Issue
Block a user