feat(runner): unify plugin execution across agents and event processors

This commit is contained in:
RockChinQ
2026-09-10 18:04:38 +08:00
parent 8903a40c41
commit f24a7c9bb2
223 changed files with 4091 additions and 3068 deletions
+10 -10
View File
@@ -842,7 +842,7 @@ test.describe('pipeline advanced flows', () => {
});
test.describe('agent runner resource selectors', () => {
test('installs an AgentRunner from the grouped empty selector and refreshes it', async ({
test('installs an Runner from the grouped empty selector and refreshes it', async ({
page,
}) => {
await installLangBotApiMocks(page, { authenticated: true });
@@ -1011,7 +1011,7 @@ test.describe('agent runner resource selectors', () => {
tags: [],
install_count: 12,
latest_version: '1.0.0',
components: { AgentRunner: 1 },
components: { Runner: 1 },
status: 'live',
type: 'plugin',
created_at: '2026-01-01T00:00:00Z',
@@ -1030,11 +1030,11 @@ test.describe('agent runner resource selectors', () => {
const runnerSelect = page.getByRole('combobox', { name: 'Runner' });
const triggerBox = await runnerSelect.boundingBox();
await runnerSelect.click();
await expect(page.getByText('Installed AgentRunners')).toBeVisible();
await expect(page.getByText('Installed Runners')).toBeVisible();
await expect(
page.getByText('No AgentRunner extension is installed yet.'),
page.getByText('No Runner extension is installed yet.'),
).toBeVisible();
await expect(page.getByText('AgentRunner Marketplace')).toBeVisible();
await expect(page.getByText('Runner Marketplace')).toBeVisible();
const selectorPopup = page.locator('[data-slot="select-content"]');
await expect(
selectorPopup.getByText('Runner used by the grouped selector test.', {
@@ -1050,7 +1050,7 @@ test.describe('agent runner resource selectors', () => {
await expect
.poll(() => marketplaceSearchBody)
.toMatchObject({
component_filter: 'AgentRunner',
component_filter: 'Runner',
type_filter: 'plugin',
});
@@ -1074,7 +1074,7 @@ test.describe('agent runner resource selectors', () => {
).toHaveCount(0);
});
test('uses the compact AgentRunner marketplace selector in pipeline AI settings', async ({
test('uses the compact Runner marketplace selector in pipeline AI settings', async ({
page,
}) => {
await installLangBotApiMocks(page, { authenticated: true });
@@ -1112,7 +1112,7 @@ test.describe('agent runner resource selectors', () => {
tags: [],
install_count: 9,
latest_version: '1.0.0',
components: { AgentRunner: 1 },
components: { Runner: 1 },
status: 'live',
type: 'plugin',
created_at: '2026-01-01T00:00:00Z',
@@ -1129,8 +1129,8 @@ test.describe('agent runner resource selectors', () => {
const runnerSelect = page.getByRole('combobox', { name: 'Runner' });
await runnerSelect.click();
await expect(page.getByText('Installed AgentRunners')).toBeVisible();
await expect(page.getByText('AgentRunner Marketplace')).toBeVisible();
await expect(page.getByText('Installed Runners')).toBeVisible();
await expect(page.getByText('Runner Marketplace')).toBeVisible();
await expect(
page
.locator('[data-slot="select-content"]')
+1 -1
View File
@@ -5,7 +5,7 @@ test('create first, select a plugin in the header, debug beside scrollable logs'
page,
}) => {
await installLangBotApiMocks(page, { authenticated: true });
const ref = 'event_processor:qa/welcome/default';
const ref = 'plugin:qa/welcome/default';
const processor = {
uuid: 'processor-qa',
kind: 'event_processor',
@@ -344,7 +344,7 @@ test.describe('wizard and QR platform regressions', () => {
await expect.poll(() => inboundTestCount).toBe(1);
});
test('blocks deployment until required AgentRunner configuration is real', async ({
test('blocks deployment until required Runner configuration is real', async ({
page,
}) => {
await installLangBotApiMocks(page, {
@@ -17,8 +17,8 @@ const kbFormSource = readSource(
const selectSource = readSource(
'src/app/home/knowledge/components/kb-form/KnowledgeEngineSelect.tsx',
);
const agentRunnerSelectSource = readSource(
'src/app/home/agents/components/AgentRunnerSelect.tsx',
const runnerSelectSource = readSource(
'src/app/home/agents/components/RunnerSelect.tsx',
);
const agentFormSource = readSource(
'src/app/home/agents/components/AgentFormComponent.tsx',
@@ -26,8 +26,8 @@ const agentFormSource = readSource(
const pipelineFormSource = readSource(
'src/app/home/pipelines/components/pipeline-form/PipelineFormComponent.tsx',
);
const agentRunnerMarketplaceSource = readSource(
'src/app/home/agents/agent-runner-marketplace.ts',
const runnerMarketplaceSource = readSource(
'src/app/home/agents/runner-marketplace.ts',
);
const marketplaceInstallButtonSource = readSource(
'src/app/home/components/MarketplaceInstallButton.tsx',
@@ -89,7 +89,7 @@ test('tracks plugin upgrades as recoverable multistep async tasks', () => {
});
test('keeps marketplace install actions on one fixed vertical column', () => {
for (const source of [selectSource, agentRunnerSelectSource]) {
for (const source of [selectSource, runnerSelectSource]) {
assert.match(source, /grid-cols-\[1\.75rem_minmax\(0,1fr\)_4rem\]/);
assert.match(source, /<MarketplaceInstallButton/);
}
@@ -112,7 +112,7 @@ test('uses a compact selected engine layout and clears stale required errors', (
});
test('installs marketplace components from inline progress buttons without selecting them', () => {
for (const source of [selectSource, agentRunnerSelectSource]) {
for (const source of [selectSource, runnerSelectSource]) {
assert.match(source, /const handleInstall = useCallback/);
assert.match(source, /installing=\{activePluginId === pluginId\}/);
assert.match(source, /progress=\{installProgress\}/);
@@ -134,18 +134,12 @@ test('installs marketplace components from inline progress buttons without selec
}
});
test('shows plugin descriptions for installed AgentRunner entries', () => {
assert.match(agentRunnerMarketplaceSource, /installedPluginDescriptions/);
assert.match(agentRunnerMarketplaceSource, /metadata\.description/);
assert.match(agentRunnerSelectSource, /installedRunnerDescription\(/);
assert.match(
agentRunnerSelectSource,
/function InstalledRunnerOptionContent/,
);
assert.match(agentRunnerSelectSource, /marketplacePlugin\?\.description/);
assert.match(
agentRunnerSelectSource,
/grid-cols-\[1\.75rem_minmax\(0,1fr\)\]/,
);
assert.doesNotMatch(agentRunnerSelectSource, /description=\{option\.name\}/);
test('shows plugin descriptions for installed Runner entries', () => {
assert.match(runnerMarketplaceSource, /installedPluginDescriptions/);
assert.match(runnerMarketplaceSource, /metadata\.description/);
assert.match(runnerSelectSource, /installedRunnerDescription\(/);
assert.match(runnerSelectSource, /function InstalledRunnerOptionContent/);
assert.match(runnerSelectSource, /marketplacePlugin\?\.description/);
assert.match(runnerSelectSource, /grid-cols-\[1\.75rem_minmax\(0,1fr\)\]/);
assert.doesNotMatch(runnerSelectSource, /description=\{option\.name\}/);
});
+2 -2
View File
@@ -40,10 +40,10 @@ test('hides the entire workspace switcher slot for a singleton local workspace',
);
});
test('keeps bot cards at the same vertical spacing as knowledge-base cards', () => {
test('keeps compact bot forms vertically spaced while detail forms support columns', () => {
assert.match(
botFormSource,
/<fieldset\s+className="[^"]*\bspace-y-6\b[^"]*"\s+disabled=\{isLoading\}/,
/<fieldset[\s\S]*?'space-y-6'[\s\S]*?disabled=\{isLoading\}/,
);
assert.match(kbFormSource, /<form[\s\S]*?className="space-y-6"/);
});
@@ -31,7 +31,8 @@ test('agent and pipeline details share the split processor workbench', () => {
/lg:grid-cols-\[minmax\(20rem,0\.72fr\)_minmax\(0,1\.28fr\)\]/,
);
assert.ok(
workbench.indexOf('{debugContent}') < workbench.indexOf('{configContent}'),
workbench.indexOf('{debugContent}') <
workbench.lastIndexOf('{configPanel}'),
);
assert.match(agentDetail, /<ProcessorDetailWorkbench/);
assert.match(agentDetail, /debugContent=/);
+9 -9
View File
@@ -12,7 +12,7 @@ const wizardSource = fs.readFileSync(
const runnerMarketplaceSource = fs.readFileSync(
path.resolve(
currentDirectory,
'../../src/app/home/agents/agent-runner-marketplace.ts',
'../../src/app/home/agents/runner-marketplace.ts',
),
'utf8',
);
@@ -66,25 +66,25 @@ test('binds every message-reply bot to its provisional pipeline before verificat
);
});
test('keeps the 4.11 AgentRunner marketplace installation flow', () => {
assert.match(wizardSource, /loadAgentRunnerCatalog\(\)/);
test('keeps the 4.11 Runner marketplace installation flow', () => {
assert.match(wizardSource, /loadRunnerCatalog\(\)/);
assert.match(
wizardSource,
/installMarketplaceAgentRunner\(plugin, \{[\s\S]*?scope: WIZARD_RUNNER_INSTALL_SCOPE/,
/installMarketplaceRunner\(plugin, \{[\s\S]*?scope: WIZARD_RUNNER_INSTALL_SCOPE/,
);
assert.match(wizardSource, /resumePendingAgentRunnerInstall\(/);
assert.match(wizardSource, /resumePendingRunnerInstall\(/);
assert.match(runnerMarketplaceSource, /RUNNER_COMPONENT_FILTER = 'Runner'/);
assert.match(runnerMarketplaceSource, /installPluginFromMarketplace\(/);
assert.match(
runnerMarketplaceSource,
/RUNNER_COMPONENT_FILTER = 'AgentRunner'/,
/const prefix = runnerPluginPrefix\(\{/,
);
assert.match(runnerMarketplaceSource, /installPluginFromMarketplace\(/);
assert.match(runnerMarketplaceSource, /const prefix = runnerPluginPrefix\(\{/);
assert.match(runnerMarketplaceSource, /option\.name\.startsWith\(prefix\)/);
assert.match(runnerMarketplaceSource, /registrationDeadline/);
assert.match(runnerMarketplaceSource, /sessionStorage\.setItem\(/);
});
test('requires the selected AgentRunner mandatory configuration before finishing', () => {
test('requires the selected Runner mandatory configuration before finishing', () => {
assert.match(
wizardSource,
/isRequiredRunnerConfigComplete\(selectedRunnerConfigItems, runnerConfig\)/,