lobehub/packages/context-engine/src/processors/InputTemplate.ts
Innei 4438b559e6
feat: add slash action tags, topic reference tool, and command bus system (#12860)
*  feat: add slash action tags in chat input

Made-with: Cursor

*  feat: enhance editor with new slash actions and localization updates

- Added new slash actions: change tone, condense, expand, polish, rewrite, summarize, and translate.
- Updated localization files for English and Chinese to include new action tags and slash commands.
- Removed deprecated useSlashItems component and integrated its functionality directly into InputEditor.

Signed-off-by: Innei <tukon479@gmail.com>

*  feat: add slash placement configuration to chat input components

- Introduced `slashPlacement` prop to `ChatInputProvider`, `StoreUpdater`, and `InputEditor` for customizable slash menu positioning.
- Updated initial state to include `slashPlacement` with default value 'top'.
- Adjusted `ChatInput` and `InputArea` components to utilize the new `slashPlacement` prop.

This enhancement allows for better control over the user interface in chat input interactions.

Signed-off-by: Innei <tukon479@gmail.com>

*  feat: implement command bus for slash action tags processing

Add command bus system to parse and execute slash commands (compact context,
new topic). Refactor action tag categories from ai/prompt to command/skill.
Add useEnabledSkills hook for dynamic skill registration.

* feat: compress command

Signed-off-by: Innei <tukon479@gmail.com>

* refactor: compress

Signed-off-by: Innei <tukon479@gmail.com>

* fix: skill inject

*  feat: slash action tags with context engine integration

Made-with: Cursor

*  feat: add topic reference builtin tool and server runtime

Made-with: Cursor

*  feat: add topic mention items and update ReferTopic integration

Made-with: Cursor

* 🐛 fix: preserve editorData through assistant-group edit flow and update RichTextMessage reactively

- EditState now forwards editorData from EditorModal to modifyMessageContent
- modifyMessageContent accepts and passes editorData to updateMessageContent
- RichTextMessage uses useEditor + effect to update document on content change instead of key-based remount
- Refactored RichTextMessage plugins to use shared createChatInputRichPlugins()

*  feat(context-engine): add metadata types and update processors/providers

Made-with: Cursor

*  feat(chat-input): add slash action tags and restore failed input state

* 🔧 chore: update package dependencies and enhance Vite configuration

- Changed @lobehub/ui dependency to a specific package URL.
- Added multiple SPA entry points and layout files to the Vite warmup configuration.
- Removed unused monorepo packages from sharedOptimizeDeps and added various dayjs locales for better localization support.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update @lobehub/ui dependency to version 5.4.0 in package.json

Signed-off-by: Innei <tukon479@gmail.com>

* 🐛 fix: correct SkillsApiName.runSkill to activateSkill and update trimmed content assertions

* 🐛 fix: resolve type errors in context-engine tests and InputEditor slashPlacement

* 🐛 fix: update runSkill to activateSkill in conversationLifecycle test

* 🐛 fix: avoid regex backtracking in placeholder parser

*  feat(localization): add action tags and tooltips for slash commands across multiple languages

Signed-off-by: Innei <tukon479@gmail.com>

* 🐛 fix: preserve file attachments when /newTopic has no text content

* cleanup

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-13 22:17:36 +08:00

89 lines
2.6 KiB
TypeScript

import debug from 'debug';
import { template } from 'es-toolkit/compat';
import { BaseProcessor } from '../base/BaseProcessor';
import type { PipelineContext, ProcessorOptions } from '../types';
declare module '../types' {
interface PipelineContextMetadataOverrides {
inputTemplateProcessed?: number;
}
}
const log = debug('context-engine:processor:InputTemplateProcessor');
export interface InputTemplateConfig {
/** Input message template string */
inputTemplate?: string;
}
/**
* Input Template Processor
* Responsible for applying input message templates to user messages
*/
export class InputTemplateProcessor extends BaseProcessor {
readonly name = 'InputTemplateProcessor';
constructor(
private config: InputTemplateConfig,
options: ProcessorOptions = {},
) {
super(options);
}
protected async doProcess(context: PipelineContext): Promise<PipelineContext> {
const clonedContext = this.cloneContext(context);
// Skip processing if no template is configured
if (!this.config.inputTemplate) {
log('No input template configured, skipping processing');
return this.markAsExecuted(clonedContext);
}
let processedCount = 0;
try {
// Compile the template
const compiler = template(this.config.inputTemplate, {
interpolate: /\{\{\s*(text)\s*\}\}/g,
});
log(`Applying input template: ${this.config.inputTemplate}`);
// Process each message
for (let i = 0; i < clonedContext.messages.length; i++) {
const message = clonedContext.messages[i];
// Only apply template to user messages
if (message.role === 'user') {
try {
const originalContent = message.content;
const processedContent = compiler({ text: originalContent });
if (processedContent !== originalContent) {
clonedContext.messages[i] = {
...message,
content: processedContent,
};
processedCount++;
log(`Applied template to message ${message.id}`);
}
} catch (error) {
log.extend('error')(`Error applying template to message ${message.id}: ${error}`);
// Keep original message on error
}
}
}
} catch (error) {
log.extend('error')(`Template compilation failed: ${error}`);
// Skip processing if template compilation fails
}
// Update metadata
clonedContext.metadata.inputTemplateProcessed = processedCount;
log(`Input template processing completed, processed ${processedCount} messages`);
return this.markAsExecuted(clonedContext);
}
}