mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-10-23 00:45:25 +08:00
Apply group response rules before busy-session steering. Initialize usable private-message and group-mention routes for new bots, including Wizard-created pipelines, and preserve member-configured rules across saves and retries. Fix empty pipeline configuration, refresh the processor sidebar after automatic creation, and show creation feedback. Align routing regressions and use Node 24 for the browser CI job. Correct the task's erroneous agent attribution while preserving every code tree and the original human contribution. Co-authored-by: multica-agent <[email protected]>
102 lines
3.1 KiB
JavaScript
102 lines
3.1 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import test from 'node:test';
|
|
import ts from 'typescript';
|
|
function load(path, deps = {}) {
|
|
const mod = { exports: {} };
|
|
new Function(
|
|
'require',
|
|
'exports',
|
|
ts.transpileModule(
|
|
fs.readFileSync(new URL('../../src/' + path, import.meta.url), 'utf8'),
|
|
{ compilerOptions: { module: ts.ModuleKind.CommonJS } },
|
|
).outputText,
|
|
)((id) => deps[id], mod.exports);
|
|
return mod.exports;
|
|
}
|
|
const template = load(
|
|
'app/home/bots/components/bot-form/message-routing-template.ts',
|
|
);
|
|
const { prepareWizardBot, wizardBindingsIfMissing } = load(
|
|
'app/wizard/bot-setup.ts',
|
|
{ '@/app/home/bots/components/bot-form/message-routing-template': template },
|
|
);
|
|
const bot = {
|
|
name: 'Wizard QA',
|
|
description: '',
|
|
adapter: 'onebot',
|
|
adapter_config: {},
|
|
enable: false,
|
|
};
|
|
test('fresh wizard binds both rules to its own pipeline and back navigation reuses the bot', async () => {
|
|
const calls = [];
|
|
let saved;
|
|
const client = {
|
|
createPipeline: async (p) => {
|
|
calls.push('pipeline');
|
|
assert.deepEqual(p.config, {});
|
|
return { uuid: 'p' };
|
|
},
|
|
createBot: async (b) => {
|
|
calls.push('bot');
|
|
saved = b;
|
|
return { uuid: 'b' };
|
|
},
|
|
getBot: async () => ({ bot: saved }),
|
|
};
|
|
const draft = { adapter: 'onebot', botUuid: null, pipelineUuid: null };
|
|
await prepareWizardBot(client, draft, bot, 'QA pipeline');
|
|
assert.deepEqual(calls, ['pipeline', 'bot']);
|
|
assert.equal(saved.event_bindings.length, 2);
|
|
assert.ok(saved.event_bindings.every((b) => b.target_uuid === 'p'));
|
|
assert.deepEqual(saved.event_bindings[1].filters[1], {
|
|
field: 'is_at_bot',
|
|
operator: 'eq',
|
|
value: true,
|
|
});
|
|
saved.adapter_config = { token: 'edited' };
|
|
assert.equal(
|
|
(await prepareWizardBot(client, draft, bot, 'QA pipeline')).bot
|
|
.adapter_config.token,
|
|
'edited',
|
|
);
|
|
assert.deepEqual(calls, ['pipeline', 'bot']);
|
|
});
|
|
test('retry after bot failure reuses the successful pipeline', async () => {
|
|
let pipelines = 0,
|
|
bots = 0;
|
|
const client = {
|
|
createPipeline: async () => ({ uuid: 'p' + ++pipelines }),
|
|
createBot: async () => {
|
|
if (++bots === 1) throw new Error('temporary failure');
|
|
return { uuid: 'b' };
|
|
},
|
|
};
|
|
const draft = { adapter: 'onebot', botUuid: null, pipelineUuid: null };
|
|
await assert.rejects(prepareWizardBot(client, draft, bot, 'p'));
|
|
await prepareWizardBot(client, draft, bot, 'p');
|
|
assert.equal(pipelines, 1);
|
|
assert.equal(bots, 2);
|
|
});
|
|
test('existing pipeline rules preserve disabled flags, filters and manual destinations', () => {
|
|
const custom = {
|
|
...bot,
|
|
event_bindings: [
|
|
{
|
|
id: 'manual',
|
|
event_pattern: '*',
|
|
target_type: 'pipeline',
|
|
target_uuid: 'existing',
|
|
filters: [],
|
|
enabled: false,
|
|
},
|
|
],
|
|
};
|
|
const before = structuredClone(custom);
|
|
assert.deepEqual(wizardBindingsIfMissing(custom, 'new'), {});
|
|
assert.deepEqual(custom, before);
|
|
const patch = wizardBindingsIfMissing(bot, 'p');
|
|
assert.equal(patch.event_bindings.length, 2);
|
|
assert.deepEqual(wizardBindingsIfMissing({ ...bot, ...patch }, 'p'), {});
|
|
});
|