본문으로 건너뛰기

프론트엔드 플러그인 API

프론트엔드 API는 브라우저 측 플러그인이 activate() 호출에서 받는 것입니다. 모든 UI 표면을 위한 등록자 집합, 이벤트 버스, i18n입니다.

진입점

프론트엔드 플러그인은 activate(api) 함수가 있는 정의를 내보냅니다. 호스트는 플러그인이 동의되고 활성화되면 FrontendPluginApi 객체로 호출합니다.

import { definePlugin } from '@neotavern/plugin-sdk';

export default definePlugin({
activate(api) {
// Register surfaces here.
},
deactivate() {
// Optional explicit teardown.
},
});

모든 등록자는 정리 함수를 반환합니다. 런타임이 자동으로 이를 모으므로 플러그인이 손으로 추적할 필요가 없습니다. 그래도 deactivate()에서 직접 관리하는 모든 것을 정리할 수 있습니다.

등록 표면

api.ui 네임스페이스는 UI 등록자를 묶습니다.

  • 페이지api.ui.pages.register({ id, path, title, mount })가 플러그인 네임스페이스 아래에 라우트를 추가합니다. mount는 호스트가 제공하는 컨테이너를 받고 정리를 반환할 수 있습니다.
  • 설정 패널api.ui.settingsPanels.register(...)가 설정 화면에 패널을 추가합니다.
  • 툴바 작업api.ui.toolbarActions.register({ id, title, icon, run }). 호스트는 작업을 표준 버튼으로 렌더링합니다. 플러그인은 의미만 제공하며 레이아웃이나 중단점은 제공하지 않습니다.
  • 메시지 작업api.ui.messageActions.register({ id, title, icon, order, placement, run }). run 콜백은 불변 메시지 스냅샷과 정리, 재호출, 타임아웃 시 발생하는 AbortSignal을 받습니다.
  • 컨텍스트 메뉴 항목context: 'message' | 'character'api.ui.contextMenuItems.register({ id, title, context, run }).
  • 메시지 렌더러api.ui.messageRenderers.register({ id, title, render }). renderplacement'replace' 또는 'after'인 일반 텍스트를 반환합니다. HTML은 절대 아닙니다.
  • 캐릭터 탭api.ui.characterTabs.register({ id, title, mount }). mount는 컨텍스트로 { characterId }를 받습니다.
  • 사이드바 패널slot: 'left' | 'right'가 있는 api.ui.sidebarPanels.register({ id, title, slot, mount }).
  • 대화상자api.ui.dialogs.register({ id, title, description, mount }).
  • 명령 팔레트 작업api.ui.commands.register({ id, title, run }).
  • 단축키api.ui.hotkeys.register({ id, combo, run }). 예: combo: 'mod+shift+k'.

슬래시 명령어는 api.slash.register({ name, description, run })로, 프롬프트 인터셉터는 api.interceptors로 별도 등록합니다.

프롬프트 인터셉터

인터셉터는 보내기 전에 조립된 프롬프트에서 실행됩니다.

api.interceptors.register({
id: 'example.format',
priority: 100,
timeoutMs: 5000,
intercept(context) {
// context.messages is an array of { id, role, content, name }.
return context;
},
});

낮은 priority가 먼저 실행되며, timeoutMs를 초과하는 플러그인은 체인을 깨지 않고 건너뜁니다. 프롬프트만 검사하는 인터셉터는 prompt.inspect가, 변경하는 인터셉터는 prompt.modify가 필요합니다.

이벤트

이벤트 버스는 타입이 있으며 호스트와 공유됩니다. api.events.on(event, handler)은 구독 해제 함수를 반환합니다.

const off = api.events.on('chat.message.created', ({ chatId, messageId }) => {
console.log('new message', chatId, messageId);
});

기본 제공 이벤트에는 chat.created, chat.opened, chat.message.created, chat.message.updated, chat.message.deleted, character.selected, generation.started, generation.delta, generation.finished, generation.error, theme.changed, language.changed가 있습니다. 플러그인은 관례에 따라 네임스페이스가 붙은 이름(예: myplugin.foo)으로 사용자 지정 이벤트를 내보내고 들을 수도 있습니다.

메시지 스냅샷과 콘텐츠 게이팅

메시지 작업은 messageId, chatId, branchId, role, content, name, meta, revision이 있는 불변 MessageActionSnapshot을 받습니다. content 필드는 플러그인이 chat.read도 보유하지 않으면 null이므로, 작업이 메시지 텍스트를 보지 않고도 메타데이터를 렌더링할 수 있습니다.

알림과 i18n

api.notify({ title, description, variant, timeoutMs })는 알림을 보여주고 닫기 함수를 반환합니다. variantinfo, success, warning, error입니다.

api.i18n은 격리된 플러그인 네임스페이스에서 번역 리소스를 관리합니다.

api.i18n.addResources('ru', { greet: 'Привет' });
const label = api.i18n.t('greet');

addResources는 다른 모든 등록과 마찬가지로 정리 함수를 반환합니다.

정리 보장

모든 등록이 정리 함수를 반환하고 런타임이 이를 추적하므로, 플러그인을 비활성화하면 모든 핸들러, 타이머, DOM 노드, 구독, 백그라운드 요청이 제거됩니다. 전체 정리 계약은 라이프사이클, 정확한 타입은 생성된 Plugin SDK 레퍼런스를 참조하세요.