Changeset 0.28.5 (#191)

This commit is contained in:
2026-03-14 22:51:50 +00:00
parent 85d5e3cc13
commit 6f0ad1355c
17 changed files with 2389 additions and 110 deletions

View File

@@ -656,6 +656,21 @@ function startRenameChat(chatId) {
// ── Send Message ─────────────────────────────
// v0.28.5: Build context object for pre-send pipe filters.
function _buildPreSendContext(opts) {
const chat = opts.channel || {};
return {
message: opts.message || '',
channel: { id: chat.id || null, type: chat.type || 'direct', title: chat.title || '' },
attachments: opts.attachments || [],
model: opts.model || null,
persona: opts.personaId || null,
metadata: {},
regenerate: opts.regenerate || false,
regenerateMessageId: opts.regenerateMessageId || null,
};
}
async function sendMessage() {
const text = ChatInput.getValue().trim();
const hasFiles = hasStagedFiles();
@@ -698,6 +713,33 @@ async function sendMessage() {
const chat = App.getActiveChat();
if (!chat) return;
// ── v0.28.5: Pre-send pipe ──────────────────────────────
// Filters can transform message, inject metadata, or halt (return null).
if (typeof sw !== 'undefined' && sw.pipe) {
const preSendCtx = _buildPreSendContext({
message: text, channel: chat, model, personaId,
attachments: fileIds, regenerate: false,
});
const result = sw.pipe._runPre(preSendCtx);
if (result === null) {
// Filter halted — suppress message
UI.toast('Message blocked by extension', 'warning');
return;
}
// Apply any mutations from filters — model/persona may have changed
// but message text is the most common mutation (KB inject, rewrite).
// Note: we don't overwrite `text` (const) — the API call reads from ctx.
var _preSendText = result.message;
var _preSendModel = result.model || model;
var _preSendPersonaId = result.persona || personaId;
var _preSendMeta = result.metadata || {};
} else {
var _preSendText = text;
var _preSendModel = model;
var _preSendPersonaId = personaId;
var _preSendMeta = {};
}
// Optimistic: show user message immediately
const userContent = text || (hasFiles ? `[${fileIds.length} file${fileIds.length > 1 ? 's' : ''} attached]` : '');
chat.messages.push({ role: 'user', content: userContent, timestamp: new Date().toISOString(), siblingCount: 1, siblingIndex: 0 });
@@ -711,7 +753,7 @@ async function sendMessage() {
UI.setGenerating(true);
try {
const resp = await API.streamCompletion(App.activeId, text, model, App.abortController.signal, modelInfo?.configId, personaId, fileIds,
const resp = await API.streamCompletion(App.activeId, _preSendText, _preSendModel, App.abortController.signal, modelInfo?.configId, _preSendPersonaId, fileIds,
typeof ToolsToggle !== 'undefined' ? ToolsToggle.getDisabledTools() : []);
// v0.23.2: Non-streaming response (DM with mention_only, no @mention)
@@ -823,6 +865,26 @@ async function regenerateMessage(messageId) {
}
}
// ── v0.28.5: Pre-send pipe (regeneration path) ──────────
if (typeof sw !== 'undefined' && sw.pipe) {
const preSendCtx = _buildPreSendContext({
message: '', channel: chat, model, personaId,
regenerate: true, regenerateMessageId: messageId,
});
const result = sw.pipe._runPre(preSendCtx);
if (result === null) {
UI.toast('Regeneration blocked by extension', 'warning');
// Restore display since we truncated above
if (chat) UI.renderMessages(chat.messages);
return;
}
var _regenModel = result.model || model;
var _regenPersonaId = result.persona || personaId;
} else {
var _regenModel = model;
var _regenPersonaId = personaId;
}
App.isGenerating = true;
App.abortController = new AbortController();
UI.setGenerating(true);
@@ -830,7 +892,7 @@ async function regenerateMessage(messageId) {
try {
const resp = await API.streamRegenerate(
App.activeId, messageId, App.abortController.signal,
model, personaId, modelInfo?.configId,
_regenModel, _regenPersonaId, modelInfo?.configId,
typeof ToolsToggle !== 'undefined' ? ToolsToggle.getDisabledTools() : []
);
await UI.streamResponse(resp, chat?.messages || [], modelInfo?.name);