AI Toolkit
Ask AI、AI Chat、インラインのプレビュー、AI Review ドロワーを備えています。すべて 1 つの aiToolkitResolver フックの上に構築されているので、今日は組み込みのデモ用リゾルバーで動かし、明日には UI を変えずに独自のバックエンドに差し替えることができます。
概要
AI Toolkit は、互いに関連する 3 つの画面をエディターに追加します。
- Ask AI — ツールバーから開くダイアログです。ワンクリックで使える 7 つのモード(校正、書き換え、短縮、拡張、要約、翻訳、理由付きの修正)、選択範囲/文書全体の対象の切り替え、適用前のインラインのプレビューがあります。
- AI Chat — 複数回のやり取りのための、ドッキングされたサイドパネルです。対象の範囲を認識し、クイックプロンプトと、AI の各応答に対するコピー/適用/挿入/置換の操作があります。
- AI Review — 保留中、承認済み、却下済みの提案を保持し続けるキューです。セッションをまたいだレビューのために、オプションでサーバー側の記録と同期できます。
3 つとも同じ aiToolkitResolver フックと同じオペレーションの仕様を共有しているので、ある画面でプレビューした提案を、別の画面で承認、却下、またはエスカレーションできます。
デモモード。リゾルバーを設定していない場合、プラグインには決定的な動作をする defaultResolveAction が用意されているので、API キーもネットワークへの呼び出しもなしに、予測どおりの出力で Ask AI、Chat、Review をローカルで動かせます。
インストール
AI Toolkit のスタイルシートとスクリプトは、エディターのコアバンドルの後に読み込みます。既定では、プラグインは読み込まれたときに、標準の default、basic、full、mobile のツールバーのプリセットに Ask AI ボタンを自動的に追加します。
<link rel="stylesheet" href="/richtexteditor/rte_theme_default.css" />
<link rel="stylesheet" href="/richtexteditor/plugins/aitoolkit.css" />
<script src="/richtexteditor/rte.js"></script>
<script src="/richtexteditor/plugins/all_plugins.js"></script>
<!-- aitoolkit.js is bundled inside all_plugins.js.
Include it separately only if you are loading plugins piecemeal. -->
<div id="editor"></div>
<script>
var editor = new RichTextEditor("#editor", {
toolbar: "full",
aiToolkitPersistenceKey: "my-editor-ai"
});
</script>設定。ダウンロードした rte.js の先頭には、プレーンテキストで書かれた編集可能な RTE_DefaultConfig ブロックがあります。これを開いて、エディターのほかのすべての設定と一緒に、AI の既定値(永続化のキー、ラベル、リゾルバーのエンドポイントなど)を変更できます。別の設定ファイルを読み込む必要はありません。AI のボタンが表示される可能性がある場合は(既定のツールバーであっても)、常に aitoolkit.css が必要です。そうでないと、AI のドロップダウンメニューのサイズが正しくなりません。AI を有効にしたままボタンの自動追加を止めるには、aiToolkitAutoToolbarButtons: false を設定し、必要なツールバーにだけ aiassist を追加してください。
var editor = new RichTextEditor("#editor", {
toolbar: "default",
aiToolkitAutoToolbarButtons: false
});3 つの画面
ツールバーから使うダイアログ。元のテキストと結果のペイン、モードの選択、対象の切り替え、変更前/変更後のプレビュー、オペレーションの計画、適用/置換/挿入/却下のボタンがあります。
ドッキングされたパネル。対象の範囲を認識したメッセージのやり取り、クイックプロンプト、メッセージの履歴、応答ごとの適用/挿入/置換の操作があります。
保持され続けるドロワー。保留中/承認済み/却下済みのキュー、一括操作、オプションのリモートの記録との同期があります。
組み込みのモード
各モードは、config.aiToolkitDialogModes 内の { id, title, description } のエントリです。Ask AI ダイアログの Action ドロップダウンに表示され、runQuickAction(id) で呼び出せます。
| id | タイトル | 既定の動作 |
|---|---|---|
proofread | Proofread | 意味を保ったまま、スペース、句読点、大文字と小文字を正規化します。 |
rewrite | Rewrite | 冗長な語句(very、really、in order to、due to the fact that)を取り除き、表現を引き締めます。 |
shorten | Shorten | 単語の最初の約 60%(最低 8 語)を残します。 |
expand | Expand | 元のテキストの下に、補足する文を追加します。 |
summarize | Summarize | 単語の最初の約 45% から、箇条書きの要約を作ります。 |
translate | Translate | 言語のラベルを付けた下書きを作ります。対象の言語は request.language として渡されます。 |
justify | Justify edit | rewrite と同じで、さらに変更を説明する reason フィールドが付きます。 |
これらは、デモ用リゾルバーのための決定的なスタブです。aiToolkitResolver を接続すると、各モードの処理方法は自分の関数が決めます。新しいモードを登録することもできます。カスタムアクションを参照してください。
aiToolkitResolver フック
これが唯一の拡張ポイントです。リゾルバーは構造化されたリクエストを受け取り、結果(または結果に解決される Promise)を返します。表示、プレビュー、レビュー、適用はエディターが処理します。
var editor = new RichTextEditor("#editor", {
toolbar: "full",
aiToolkitResolver: async function (request) {
var reply = await fetch("/api/ai", {
method: "POST",
body: JSON.stringify({
mode: request.mode,
text: request.source,
language: request.language
})
}).then(function (r) { return r.json(); });
return {
result: reply.text, // string: the AI output
reason: reply.explanation, // string: why this change
operations: [{ // structured plan (optional)
type: "preview-suggestion",
text: reply.text,
reason: reply.explanation
}]
};
}
});リクエストの形
| フィールド | 型 | 意味 |
|---|---|---|
actionId | string | ユーザーが呼び出したアクション(登録されたアクションまたはモードの id と一致します)。 |
mode | string | ダイアログのモード。proofread、rewrite、translate など。 |
source | string | 処理対象のテキスト。選択範囲があればそのテキスト、なければ文書全体のテキスト。 |
prompt | string | ユーザーのプロンプトのテキスト(チャットモード用)。 |
language | string | 翻訳モードの対象の言語。それ以外では空です。 |
scope | string | "selection" または "document"。 |
selectionText | string | 選択範囲のテキスト(空の場合があります)。 |
documentText | string | 文書全体のテキスト。 |
snapshot | object | 選択範囲のスナップショット(hasSelection、rangeHTML、text、wholeText など)。 |
editor | RichTextEditor | エディターのインスタンス。 |
contract | object | サポートされているオペレーションの種類の全一覧(検証用)。 |
レスポンスの形
次のフィールドを任意に含む、単純なオブジェクトを返します。すべて省略可能なので、不要なものは省いてください。
| フィールド | 型 | 意味 |
|---|---|---|
result | string | AI の生の出力。結果のペインに表示され、既定の提案の本文として使われます。 |
reason | string | AI がこの変更を勧める理由。「Why this suggestion」パネルに表示されます。 |
message | string | チャット形式の返信(AI Chat の画面のみ)。 |
operations | Operation[] | 構造化された計画。オペレーションの種類を参照してください。 |
target | string | 適用する場所。"selection-preview"、"document"、"insert" など。 |
autoRun | boolean | ユーザーの確認なしに自動で適用します(控えめに使ってください)。 |
文字列や Promise を返すこともできます。文字列は { result: <that string> } になり、Promise は await されます。
オペレーションの種類
オペレーションは、リゾルバーが返せる構造化された計画です。エディターはそれらを順に実行します(または、計画のパネルからユーザーの操作で 1 つずつ実行します)。
| type | フィールド | 動作 |
|---|---|---|
preview-suggestion | text, reason? | インラインで変更前/変更後のプレビューを表示します。ユーザーが承認または却下します。 |
replace-selection | text | 現在の選択範囲を、指定したテキストで置き換えます。 |
replace-document | text | 文書の本文全体を置き換えます。 |
insert-below | text | キャレットまたは選択範囲の後に、新しいブロックを挿入します。 |
add-comment | text, reason? | 現在の選択範囲に、内容を変更しない AI のコメントのマーカーを付けます。 |
open-chat-panel | message? | AI Chat パネルを開きます。必要に応じて、最初のメッセージを入れておきます。 |
open-review-panel | - | AI Review ドロワーを開きます。 |
独自のオペレーションの種類は、editor.aiToolkit.registerOperationHandler(type, handler) で登録できます。
editor.aiToolkit.registerOperationHandler("insert-callout", function (op, ctx) {
// ctx = { snapshot, resolved, request, action, editor }
ctx.editor.insertHTML(
'<aside class="callout">' + ctx.editor.htmlEncode(op.text) + '</aside>'
);
return true; // mark the operation as handled
});プログラムからの API
すべての画面は、editor.aiToolkit を通じてコードから開いて操作できます。
// Open the Ask AI dialog
editor.aiToolkit.openDialog({ presetMode: "rewrite", autoRun: false });
// Quick actions (no dialog) - target: selection if present, else whole document
editor.aiToolkit.runQuickAction("proofread");
editor.aiToolkit.runQuickAction("translate", { language: "spanish" });
// Panels
editor.aiToolkit.openChatPanel({ focusComposer: true });
editor.aiToolkit.openReviewPanel({ focusPanel: true });
editor.aiToolkit.closeChatPanel();
editor.aiToolkit.closeReviewPanel();
editor.aiToolkit.toggleChatPanel();
editor.aiToolkit.toggleReviewPanel();
// Resolve without rendering - useful for tests + headless flows
editor.aiToolkit.resolveAction("rewrite", { source: "hello world" })
.then(function (resolved) { console.log(resolved.result); });
// Swap the resolver at runtime
editor.aiToolkit.setResolver(myResolver);
// Review queue
var pending = editor.aiToolkit.getSuggestions();
editor.aiToolkit.clearSuggestions();
editor.aiToolkit.saveSuggestionLedger();
editor.aiToolkit.loadSuggestionLedger();カスタムのアクションとモード
分野に特化したアクション(SEO 向けの書き換え、法的な条項のチェック、文体の統一など)を登録できます。それらは同じダイアログ、チャット、レビューの UI に組み込まれます。
// Add a new dialog mode (appears in the Action dropdown)
editor.aiToolkit.registerDialogMode({
id: "seo",
title: "SEO rewrite",
description: "Rewrite for stronger keyword coverage while preserving meaning."
});
// Register the action with a target (where output goes by default)
editor.aiToolkit.registerAction({
id: "seo",
title: "SEO rewrite",
target: "selection-preview",
resolverMode: "seo" // passed as request.mode to your resolver
});
// Your resolver handles it just like built-in modes
config.aiToolkitResolver = function (request) {
if (request.mode === "seo") { /* call your SEO service */ }
/* ... */
};永続化とリモートの記録
AI Review ドロワーの提案は、自分で指定するキーで localStorage に保存されます。エディターのインスタンスごと(たとえば文書ごと)に範囲を分けるには、aiToolkitPersistenceKey を設定してください。
new RichTextEditor("#editor", {
aiToolkitPersistenceKey: "doc-42-review", // localStorage scope
aiToolkitSuggestionLedgerUrl: "/api/ai/ledger", // optional GET/POST for cross-session sync
aiToolkitReviewLogUrl: "/api/ai/review-log", // optional activity feed endpoint
aiToolkitReviewSyncInterval: 15000 // ms between sync polls (default 15s)
});記録の URL を設定すると、プラグインは開いたときに GET し、承認/却下のときに POST するので、レビューのキューがセッションをまたいで残り、レビュー担当者の間で共有されます。
BYOK(独自のキーの持ち込み)
重要:エディターは API キーを受け付けることも保存することもありません。キーはサーバー側のシークレットマネージャーに置くものです。
推奨される BYOK のパターンは次のとおりです。
- 管理用の UI で、テナントがプロバイダーを選んでキーを貼り付けます。フォームはバックエンドに POST します。
- バックエンドは、テナント単位でキーをシークレットマネージャーに書き込みます。
- エディターの
aiToolkitResolverは、セッションの Cookie を付けて/api/aiに POST します。ブラウザーにキーはありません。 - バックエンドはテナントのキーを調べてプロバイダーを呼び出し、必要な部分だけに整えたレスポンスを返します。
動作する管理用のフォーム、振り分けを行うリゾルバー、Express 風のサーバーの概略については、BYOK のデモを参照してください。
設定リファレンス
| オプション | 型 | 既定値 | 用途 |
|---|---|---|---|
aiToolkitEnabled | boolean | true | false にすると、プラグイン全体を無効にします(ボタンの追加も API もなし)。 |
aiToolkitAutoToolbarButtons | boolean | true | 標準のツールバーと、テキスト選択時のフローティングツールバーへの AI ボタンの自動追加を制御します。コードから AI を使えるようにしたまま、aiassist の配置を自分で管理するには false にします。 |
aiToolkitResolver | function | null | 自分で用意するフック。リゾルバーを参照してください。ない場合は組み込みのデモ用リゾルバーを使います。 |
aiToolkitActions | Action[] | 組み込み | 登録されたアクションの全一覧。拡張するには registerAction を使います。 |
aiToolkitDialogModes | Mode[] | 7 つの組み込み | Ask AI のドロップダウンに表示されるモード。 |
aiToolkitOperationHandlers | object | {} | 独自のオペレーションの種類のハンドラー。type をキーにします。 |
aiToolkitPersistenceKey | string | "" | レビューのキューの localStorage の範囲。空の場合は永続化しません。 |
aiToolkitSuggestionLedgerUrl | string | "" | 共有の記録を同期するサーバーのエンドポイント。 |
aiToolkitReviewLogUrl | string | "" | レビューの活動のフィードを送るサーバーのエンドポイント。 |
aiToolkitReviewSyncInterval | number | 15000 | 記録をポーリングする間隔(ミリ秒)。 |
aiToolkitLabel | string | "Current editor" | Ask AI ダイアログ内のメタ情報のピルに表示されるラベル。 |
text_aiassist | string | "Ask AI" | ツールチップとダイアログのタイトル(UI の言語ごとにローカライズします)。 |
試してみる
上記のすべての画面は、公開デモで API キーなしで動作します。
- AI Toolkit のデモ — Ask AI、クイックアクション、Chat、Review ドロワー
- BYOK のデモ — 管理用の設定フォーム、振り分けを行うリゾルバー、サーバー側の概略
- AI Toolkit の概要 — 実際に動くエディターのモックアップを含む紹介ページ