prosemirror-suggestcat-plugin 1.1.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +291 -158
- package/dist/api/config.d.ts +7 -0
- package/dist/api/index.d.ts +4 -0
- package/dist/api/request.d.ts +16 -0
- package/dist/api/streaming.d.ts +16 -0
- package/dist/api/types.d.ts +30 -0
- package/dist/autoComplete/actions.d.ts +33 -0
- package/dist/autoComplete/index.d.ts +35 -0
- package/dist/autoComplete/plugin.d.ts +14 -0
- package/dist/autoComplete/streaming.d.ts +48 -0
- package/dist/autoComplete/types.d.ts +68 -0
- package/dist/blockRunner/defaults.d.ts +3 -0
- package/dist/blockRunner/examples/linkDetector/decorations.d.ts +3 -0
- package/dist/blockRunner/examples/linkDetector/index.d.ts +4 -0
- package/dist/blockRunner/examples/linkDetector/plugin.d.ts +5 -0
- package/dist/blockRunner/examples/linkDetector/processor.d.ts +4 -0
- package/dist/blockRunner/examples/linkDetector/types.d.ts +8 -0
- package/dist/blockRunner/examples/randomProcessor/decorations.d.ts +4 -0
- package/dist/blockRunner/examples/randomProcessor/index.d.ts +4 -0
- package/dist/blockRunner/examples/randomProcessor/plugin.d.ts +5 -0
- package/dist/blockRunner/examples/randomProcessor/processor.d.ts +5 -0
- package/dist/blockRunner/examples/randomProcessor/types.d.ts +14 -0
- package/dist/blockRunner/examples/sentenceLength/decorations.d.ts +3 -0
- package/dist/blockRunner/examples/sentenceLength/index.d.ts +4 -0
- package/dist/blockRunner/examples/sentenceLength/plugin.d.ts +5 -0
- package/dist/blockRunner/examples/sentenceLength/processor.d.ts +5 -0
- package/dist/blockRunner/examples/sentenceLength/types.d.ts +12 -0
- package/dist/blockRunner/examples/wordComplexity/decorations.d.ts +3 -0
- package/dist/blockRunner/examples/wordComplexity/index.d.ts +4 -0
- package/dist/blockRunner/examples/wordComplexity/plugin.d.ts +5 -0
- package/dist/blockRunner/examples/wordComplexity/processor.d.ts +6 -0
- package/dist/blockRunner/examples/wordComplexity/types.d.ts +13 -0
- package/dist/blockRunner/executor.d.ts +7 -0
- package/dist/blockRunner/executor.test.d.ts +1 -0
- package/dist/blockRunner/index.d.ts +12 -0
- package/dist/blockRunner/plugin.d.ts +14 -0
- package/dist/blockRunner/state.d.ts +4 -0
- package/dist/blockRunner/state.test.d.ts +1 -0
- package/dist/blockRunner/testHelpers.d.ts +17 -0
- package/dist/blockRunner/types.d.ts +162 -0
- package/dist/blockRunner/utils.d.ts +25 -0
- package/dist/blockRunner/utils.test.d.ts +1 -0
- package/dist/completeV2/actions.d.ts +30 -0
- package/dist/completeV2/index.d.ts +4 -0
- package/dist/completeV2/plugin.d.ts +7 -0
- package/dist/completeV2/streaming.d.ts +26 -0
- package/dist/completeV2/types.d.ts +71 -0
- package/dist/grammarSuggestV2/actions.d.ts +17 -0
- package/dist/grammarSuggestV2/decorations.d.ts +5 -0
- package/dist/grammarSuggestV2/index.d.ts +5 -0
- package/dist/grammarSuggestV2/modelState.d.ts +11 -0
- package/dist/grammarSuggestV2/plugin.d.ts +7 -0
- package/dist/grammarSuggestV2/processor.d.ts +11 -0
- package/dist/grammarSuggestV2/types.d.ts +42 -0
- package/dist/index.d.ts +9 -5
- package/dist/index.es.js +1 -1
- package/dist/index.js +1 -1
- package/dist/styles/styles.css +142 -43
- package/dist/types.d.ts +32 -8
- package/dist/utils.d.ts +3 -0
- package/package.json +16 -3
- package/dist/completePlugin.d.ts +0 -3
- package/dist/eventHandlers.d.ts +0 -9
- package/dist/makeRequest.d.ts +0 -4
- package/dist/makeTaksRequest.d.ts +0 -6
- package/dist/plugin.d.ts +0 -3
package/README.md
CHANGED
|
@@ -8,21 +8,34 @@
|
|
|
8
8
|
|
|
9
9
|

|
|
10
10
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
11
|
+
- AI-powered grammar and style corrections for ProseMirror
|
|
12
|
+
- AI text completion, rewriting, translation, tone changes and more — with streaming
|
|
13
|
+
- Inline autocomplete with ghost text (like GitHub Copilot)
|
|
14
|
+
- Paragraph-level processing with dirty state tracking and parallel execution
|
|
15
|
+
- Multiple AI model support with automatic fallback
|
|
14
16
|
|
|
15
|
-
##
|
|
17
|
+
## Getting started
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
1. Create an account on [SuggestCat](https://www.suggestcat.com/) and generate an API key
|
|
20
|
+
2. Install the package
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
npm i prosemirror-suggestcat-plugin
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
3. Add the plugins you need to your ProseMirror (or TipTap) editor using your API key
|
|
27
|
+
4. Import the styles or write your own CSS
|
|
28
|
+
5. Track your usage and manage API keys on your [admin dashboard](https://www.suggestcat.com/)
|
|
29
|
+
|
|
30
|
+
## Grammar suggestion plugin
|
|
31
|
+
|
|
32
|
+
Checks your text for grammar and style issues paragraph by paragraph. Only edited paragraphs are re-checked, and multiple paragraphs are processed in parallel.
|
|
21
33
|
|
|
22
34
|
```typescript
|
|
23
35
|
import {
|
|
24
|
-
|
|
25
|
-
|
|
36
|
+
grammarSuggestPluginV2,
|
|
37
|
+
grammarSuggestV2Key,
|
|
38
|
+
ActionType,
|
|
26
39
|
} from "prosemirror-suggestcat-plugin";
|
|
27
40
|
|
|
28
41
|
const view = new EditorView(document.querySelector("#editor"), {
|
|
@@ -30,214 +43,334 @@ const view = new EditorView(document.querySelector("#editor"), {
|
|
|
30
43
|
doc: schema.nodeFromJSON(initialDoc),
|
|
31
44
|
plugins: [
|
|
32
45
|
...exampleSetup({ schema }),
|
|
33
|
-
|
|
34
|
-
|
|
46
|
+
grammarSuggestPluginV2("<YOUR_API_KEY>", {
|
|
47
|
+
debounceMs: 1000,
|
|
48
|
+
batchSize: 4,
|
|
35
49
|
}),
|
|
36
50
|
],
|
|
37
51
|
}),
|
|
38
52
|
});
|
|
53
|
+
|
|
54
|
+
// Initialize the grammar checker
|
|
55
|
+
view.dispatch(
|
|
56
|
+
view.state.tr.setMeta(grammarSuggestV2Key, {
|
|
57
|
+
type: ActionType.INIT,
|
|
58
|
+
metadata: {},
|
|
59
|
+
}),
|
|
60
|
+
);
|
|
39
61
|
```
|
|
40
62
|
|
|
41
63
|
### Options
|
|
42
64
|
|
|
43
|
-
- `GrammarSuggestPluginOptions`
|
|
44
|
-
|
|
45
65
|
```typescript
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
66
|
+
interface GrammarSuggestV2Options {
|
|
67
|
+
apiKey: string;
|
|
68
|
+
apiEndpoint?: string;
|
|
69
|
+
model?: string | AIModel;
|
|
70
|
+
fallback?: {
|
|
71
|
+
fallbackModel: string | AIModel;
|
|
72
|
+
failureThreshold?: number; // default: 3
|
|
73
|
+
};
|
|
74
|
+
batchSize?: number; // parallel workers, default: 4
|
|
75
|
+
maxRetries?: number; // default: 3
|
|
76
|
+
backoffBase?: number; // default: 2000ms
|
|
77
|
+
debounceMs?: number; // default: 1000ms
|
|
78
|
+
createPopup?: (
|
|
49
79
|
view: EditorView,
|
|
50
80
|
decoration: Decoration,
|
|
51
81
|
pos: number,
|
|
52
|
-
applySuggestion: (
|
|
53
|
-
discardSuggestion: (
|
|
82
|
+
applySuggestion: () => void,
|
|
83
|
+
discardSuggestion: () => void,
|
|
84
|
+
requestHint: () => Promise<string>,
|
|
54
85
|
) => HTMLElement;
|
|
55
|
-
}
|
|
86
|
+
}
|
|
56
87
|
```
|
|
57
88
|
|
|
58
|
-
|
|
89
|
+
### Styles
|
|
59
90
|
|
|
60
91
|
```typescript
|
|
61
|
-
|
|
62
|
-
debounceMs: 2000,
|
|
63
|
-
createUpdatePopup,
|
|
64
|
-
};
|
|
92
|
+
import "prosemirror-suggestcat-plugin/dist/styles/styles.css";
|
|
65
93
|
```
|
|
66
94
|
|
|
67
|
-
|
|
95
|
+
Or style the decorations yourself using these CSS classes:
|
|
96
|
+
|
|
97
|
+
- `.grammarSuggestionV2` — inline decoration on suggestions
|
|
98
|
+
- `.removalSuggestionV2` — when the suggestion is a deletion
|
|
99
|
+
- `.grammarSuggestionV2-selected` — currently selected suggestion
|
|
100
|
+
- `.grammarPopupV2` — popup container
|
|
68
101
|
|
|
69
|
-
|
|
102
|
+
## Complete plugin
|
|
103
|
+
|
|
104
|
+
AI text completion and transformation with streaming support. Use it to complete, shorten, lengthen, simplify, explain, translate text and more.
|
|
70
105
|
|
|
71
106
|
```typescript
|
|
72
|
-
import "prosemirror-suggestcat-plugin
|
|
107
|
+
import { completePluginV2 } from "prosemirror-suggestcat-plugin";
|
|
108
|
+
|
|
109
|
+
const view = new EditorView(document.querySelector("#editor"), {
|
|
110
|
+
state: EditorState.create({
|
|
111
|
+
doc: schema.nodeFromJSON(initialDoc),
|
|
112
|
+
plugins: [
|
|
113
|
+
...exampleSetup({ schema }),
|
|
114
|
+
completePluginV2("<YOUR_API_KEY>", {
|
|
115
|
+
maxSelection: 1000,
|
|
116
|
+
}),
|
|
117
|
+
],
|
|
118
|
+
}),
|
|
119
|
+
});
|
|
73
120
|
```
|
|
74
121
|
|
|
75
|
-
|
|
122
|
+
### Triggering tasks
|
|
76
123
|
|
|
77
|
-
|
|
124
|
+
Use action functions instead of dispatching metas directly:
|
|
78
125
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
126
|
+
```typescript
|
|
127
|
+
import {
|
|
128
|
+
startTask,
|
|
129
|
+
acceptResult,
|
|
130
|
+
rejectResult,
|
|
131
|
+
cancelTask,
|
|
132
|
+
getCompleteState,
|
|
133
|
+
AiPromptsWithoutParam,
|
|
134
|
+
AiPromptsWithParam,
|
|
135
|
+
MoodParamType,
|
|
136
|
+
TranslationTargetLanguage,
|
|
137
|
+
} from "prosemirror-suggestcat-plugin";
|
|
88
138
|
|
|
89
|
-
|
|
139
|
+
// Continue writing from cursor
|
|
140
|
+
startTask(view, AiPromptsWithoutParam.Complete);
|
|
90
141
|
|
|
91
|
-
|
|
92
|
-
.
|
|
93
|
-
|
|
94
|
-
|
|
142
|
+
// Transform selected text
|
|
143
|
+
startTask(view, AiPromptsWithoutParam.MakeShorter);
|
|
144
|
+
startTask(view, AiPromptsWithoutParam.MakeLonger);
|
|
145
|
+
startTask(view, AiPromptsWithoutParam.Simplify);
|
|
146
|
+
startTask(view, AiPromptsWithoutParam.Explain);
|
|
147
|
+
startTask(view, AiPromptsWithoutParam.ActionItems);
|
|
148
|
+
startTask(view, AiPromptsWithoutParam.Improve);
|
|
95
149
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
150
|
+
// Tasks with parameters
|
|
151
|
+
startTask(view, AiPromptsWithParam.ChangeTone, {
|
|
152
|
+
mood: MoodParamType.Friendly,
|
|
153
|
+
});
|
|
154
|
+
startTask(view, AiPromptsWithParam.Translate, {
|
|
155
|
+
targetLanguage: TranslationTargetLanguage.Spanish,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Accept or reject the result once streaming finishes
|
|
159
|
+
acceptResult(view);
|
|
160
|
+
rejectResult(view);
|
|
161
|
+
|
|
162
|
+
// Cancel an in-progress task
|
|
163
|
+
cancelTask(view);
|
|
99
164
|
```
|
|
100
165
|
|
|
101
|
-
###
|
|
166
|
+
### State flow
|
|
102
167
|
|
|
103
|
-
|
|
104
|
-
|
|
168
|
+
```
|
|
169
|
+
IDLE -> PENDING -> STREAMING -> PREVIEW -> APPLYING -> IDLE
|
|
170
|
+
```
|
|
105
171
|
|
|
106
|
-
|
|
172
|
+
During `STREAMING` the result is built up incrementally. At `PREVIEW` you can accept or reject. Only one task runs at a time.
|
|
107
173
|
|
|
108
|
-
|
|
174
|
+
## Autocomplete plugin
|
|
109
175
|
|
|
110
|
-
|
|
111
|
-
import {
|
|
112
|
-
completePluginKey,
|
|
113
|
-
completePlugin,
|
|
114
|
-
defaultCompleteOptions,
|
|
115
|
-
completePluginKey,
|
|
116
|
-
} from "prosemirror-suggestcat-plugin";
|
|
176
|
+
Inline ghost-text completions that appear after the cursor as you type. Press **Tab** to accept, **Escape** to dismiss.
|
|
117
177
|
|
|
118
|
-
|
|
178
|
+
```typescript
|
|
179
|
+
import { autoCompletePlugin } from "prosemirror-suggestcat-plugin";
|
|
180
|
+
|
|
181
|
+
const view = new EditorView(document.querySelector("#editor"), {
|
|
119
182
|
state: EditorState.create({
|
|
120
183
|
doc: schema.nodeFromJSON(initialDoc),
|
|
121
184
|
plugins: [
|
|
122
185
|
...exampleSetup({ schema }),
|
|
123
|
-
|
|
186
|
+
autoCompletePlugin("<YOUR_API_KEY>", {
|
|
187
|
+
debounceMs: 500,
|
|
188
|
+
maxContextLength: 2000,
|
|
189
|
+
}),
|
|
124
190
|
],
|
|
125
191
|
}),
|
|
126
192
|
});
|
|
127
193
|
```
|
|
128
194
|
|
|
129
|
-
|
|
130
|
-
- `maxSelection` defaults to 1000 - can controll how long text will be sent to AI to transform it
|
|
195
|
+
### Options
|
|
131
196
|
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
|
|
197
|
+
```typescript
|
|
198
|
+
interface AutoCompleteOptions {
|
|
199
|
+
debounceMs: number; // default: 500
|
|
200
|
+
maxContextLength: number; // default: 2000
|
|
201
|
+
apiEndpoint?: string;
|
|
202
|
+
model?: string;
|
|
203
|
+
ghostTextClass?: string; // default: "autoCompleteGhostText"
|
|
135
204
|
}
|
|
136
205
|
```
|
|
137
206
|
|
|
138
|
-
|
|
207
|
+
### Styles
|
|
139
208
|
|
|
140
|
-
|
|
141
|
-
- send the plugin a task using `setMeta` using the `completePluginKey` plugin key
|
|
209
|
+
Add CSS for the ghost text:
|
|
142
210
|
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
);
|
|
211
|
+
```css
|
|
212
|
+
.autoCompleteGhostText {
|
|
213
|
+
color: #9ca3af;
|
|
214
|
+
opacity: 0.7;
|
|
215
|
+
pointer-events: none;
|
|
216
|
+
}
|
|
150
217
|
```
|
|
151
218
|
|
|
152
|
-
|
|
219
|
+
### Programmatic control
|
|
153
220
|
|
|
154
|
-
|
|
155
|
-
|
|
221
|
+
```typescript
|
|
222
|
+
import {
|
|
223
|
+
setAutoCompleteEnabled,
|
|
224
|
+
acceptAutoCompletion,
|
|
225
|
+
dismissAutoCompletion,
|
|
226
|
+
isAutoCompleteEnabled,
|
|
227
|
+
hasAutoCompletion,
|
|
228
|
+
} from "prosemirror-suggestcat-plugin";
|
|
156
229
|
|
|
157
|
-
|
|
158
|
-
view
|
|
159
|
-
view.state.tr.setMeta(completePluginKey, {
|
|
160
|
-
type: "Complete",
|
|
161
|
-
status: "accpeted",
|
|
162
|
-
}),
|
|
163
|
-
);
|
|
164
|
-
```
|
|
230
|
+
setAutoCompleteEnabled(view, true);
|
|
231
|
+
setAutoCompleteEnabled(view, false);
|
|
165
232
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
- the plugin takes care of replacing existing text, or appending the completion result to the end of your document
|
|
171
|
-
- `MakeLonger/MakeShorter` - requires a selection, which content to make shorter or longer
|
|
172
|
-
|
|
173
|
-
```ts
|
|
174
|
-
export enum TaskType {
|
|
175
|
-
Complete = "Complete",
|
|
176
|
-
Improve = "Improve",
|
|
177
|
-
MakeLonger = "MakeLonger",
|
|
178
|
-
MakeShorter = "MakeShorter",
|
|
179
|
-
Simplify = "Simplify",
|
|
180
|
-
Explain = "Explain",
|
|
181
|
-
ActionItems = "ActionItems",
|
|
182
|
-
}
|
|
183
|
-
export enum OpenAiPromptsWithParam {
|
|
184
|
-
ChangeTone = "ChangeTone",
|
|
185
|
-
Translate = "Translate",
|
|
233
|
+
if (hasAutoCompletion(view)) {
|
|
234
|
+
acceptAutoCompletion(view);
|
|
235
|
+
// or
|
|
236
|
+
dismissAutoCompletion(view);
|
|
186
237
|
}
|
|
238
|
+
```
|
|
187
239
|
|
|
188
|
-
|
|
189
|
-
idle = "idle",
|
|
190
|
-
new = "new",
|
|
191
|
-
streaming = "streaming",
|
|
192
|
-
finished = "finished",
|
|
193
|
-
accepted = "accepted",
|
|
194
|
-
rejected = "rejected",
|
|
195
|
-
done = "done",
|
|
196
|
-
error = "error",
|
|
197
|
-
}
|
|
240
|
+
## How it works
|
|
198
241
|
|
|
199
|
-
|
|
200
|
-
type?: TaskType;
|
|
201
|
-
status?: Status;
|
|
202
|
-
result?: string;
|
|
203
|
-
selection?: TextSelection;
|
|
204
|
-
error?: string;
|
|
205
|
-
}
|
|
242
|
+
### API
|
|
206
243
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
244
|
+
All plugins communicate with the SuggestCat backend through a shared API module. You can configure the endpoint and model per plugin, or use the defaults (`openai:gpt-4o-mini`).
|
|
245
|
+
|
|
246
|
+
The module exposes two request functions if you need to use them directly:
|
|
247
|
+
|
|
248
|
+
- `grammarRequest(options)` — a non-streaming POST that returns the corrected text and a list of modifications
|
|
249
|
+
- `streamingRequest(options, callbacks)` — a streaming request with `onChunk`, `onComplete` and `onError` callbacks, used by the complete and autocomplete plugins. Supports cancellation via `AbortSignal`.
|
|
250
|
+
|
|
251
|
+
Both accept an `ApiConfig` (`apiKey`, optional `endpoint`, optional `model`). You can use `createApiConfig` or `createGrammarApiConfig` to fill in defaults.
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
import {
|
|
255
|
+
streamingRequest,
|
|
256
|
+
grammarRequest,
|
|
257
|
+
createApiConfig,
|
|
258
|
+
createGrammarApiConfig,
|
|
259
|
+
} from "prosemirror-suggestcat-plugin";
|
|
211
260
|
```
|
|
212
261
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
262
|
+
### Block runner
|
|
263
|
+
|
|
264
|
+
The grammar suggestion plugin is built on top of a generic **block runner** framework. Instead of sending the entire document to the API, it splits the document into processing units (paragraphs by default) and processes them in parallel.
|
|
265
|
+
|
|
266
|
+
Key properties:
|
|
267
|
+
|
|
268
|
+
- **Paragraph-level processing** — each paragraph is an independent unit, so large documents don't result in oversized API calls
|
|
269
|
+
- **Dirty state tracking** — when a paragraph is edited, only that unit is marked dirty and re-processed after a debounce delay. The plugin skips dirty marking for its own document changes (e.g. applying a suggestion)
|
|
270
|
+
- **Parallel execution** — multiple units are processed concurrently, controlled by `batchSize`. A unit goes through `QUEUED → PROCESSING → DONE` (or `BACKOFF → retry` on failure)
|
|
271
|
+
- **Retry with backoff** — failed units are retried up to `maxRetries` times with exponential backoff
|
|
272
|
+
|
|
273
|
+
The block runner is also exported as a standalone building block. You can use it to build your own paragraph-level processing plugins. The package includes a few example plugins (link detector, word complexity, sentence length) that demonstrate how to wire up a custom processor.
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
import {
|
|
277
|
+
blockRunnerPlugin,
|
|
278
|
+
createBlockRunnerKey,
|
|
279
|
+
ActionType,
|
|
280
|
+
dispatchAction,
|
|
281
|
+
} from "prosemirror-suggestcat-plugin";
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
To create a block runner plugin, provide a `pluginKey`, a `unitProcessor` (async function that receives a processing unit and returns a result), a `decorationFactory` (turns results into ProseMirror decorations), and optionally a `widgetFactory` (shows per-unit status indicators) and a `decorationTransformer` (filters/modifies decorations based on context state).
|
|
285
|
+
|
|
286
|
+
#### Helper functions
|
|
287
|
+
|
|
288
|
+
The block runner exports utility functions you can use in your processor or elsewhere:
|
|
289
|
+
|
|
290
|
+
- `extractTextWithMapping(doc, from, to)` — extracts text from a document range and builds a position mapping between text offsets and doc positions
|
|
291
|
+
- `textToDocPos(textPos, mapping)` — converts a text-space position back to a document position using the mapping
|
|
292
|
+
- `getUnitsInRange(doc, from, to, nodeTypes?)` — finds all matching nodes in a range
|
|
293
|
+
- `createUnitsFromDocument(doc, from, to, metadataFactory, nodeTypes?)` — creates processing units from document nodes
|
|
294
|
+
- `getProgress(state)` — returns `{ completed, total, decorations }` for progress tracking
|
|
295
|
+
- `calculateBackoff(retryCount, baseMs)` — computes the backoff delay for retries
|
|
296
|
+
- `allUnitsFinished(units)` — checks if all units are in a terminal state (DONE or ERROR)
|
|
297
|
+
|
|
298
|
+
#### Manual transactions
|
|
299
|
+
|
|
300
|
+
You can control the block runner by dispatching actions via `dispatchAction(view, pluginKey, action)`:
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
import { dispatchAction, ActionType } from "prosemirror-suggestcat-plugin";
|
|
304
|
+
|
|
305
|
+
// Initialize — creates units from the document and starts processing
|
|
306
|
+
dispatchAction(view, myPluginKey, {
|
|
307
|
+
type: ActionType.INIT,
|
|
308
|
+
metadata: {},
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
// Pause processing
|
|
312
|
+
dispatchAction(view, myPluginKey, { type: ActionType.FINISH });
|
|
313
|
+
|
|
314
|
+
// Resume paused processing
|
|
315
|
+
dispatchAction(view, myPluginKey, { type: ActionType.RESUME });
|
|
316
|
+
|
|
317
|
+
// Clear all state
|
|
318
|
+
dispatchAction(view, myPluginKey, { type: ActionType.CLEAR });
|
|
319
|
+
|
|
320
|
+
// Remove a specific decoration
|
|
321
|
+
dispatchAction(view, myPluginKey, {
|
|
322
|
+
type: ActionType.REMOVE_DECORATION,
|
|
323
|
+
id: decorationId,
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
// Update context state (e.g. for filtering or selection)
|
|
327
|
+
dispatchAction(view, myPluginKey, {
|
|
328
|
+
type: ActionType.UPDATE_CONTEXT,
|
|
329
|
+
contextState: { selectedSuggestionId: someId },
|
|
330
|
+
});
|
|
243
331
|
```
|
|
332
|
+
|
|
333
|
+
There are also convenience wrappers: `pauseRunner(view, pluginKey)`, `resumeRunner(view, pluginKey)`, and `canResume(state)`.
|
|
334
|
+
|
|
335
|
+
## Available models
|
|
336
|
+
|
|
337
|
+
All plugins accept a `model` option:
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
type AIModel =
|
|
341
|
+
| "openai:gpt-4o"
|
|
342
|
+
| "openai:gpt-4o-mini" // default
|
|
343
|
+
| "cerebras:llama-3.1-8b"
|
|
344
|
+
| "cerebras:llama-3.3-70b"
|
|
345
|
+
| "cerebras:qwen-3-32b";
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
## TipTap
|
|
349
|
+
|
|
350
|
+
All plugins work with TipTap by wrapping them in an extension:
|
|
351
|
+
|
|
352
|
+
```typescript
|
|
353
|
+
import { Extension } from "@tiptap/core";
|
|
354
|
+
import {
|
|
355
|
+
grammarSuggestPluginV2,
|
|
356
|
+
grammarSuggestV2Key,
|
|
357
|
+
ActionType,
|
|
358
|
+
completePluginV2,
|
|
359
|
+
autoCompletePlugin,
|
|
360
|
+
} from "prosemirror-suggestcat-plugin";
|
|
361
|
+
|
|
362
|
+
const SuggestCatExtension = Extension.create({
|
|
363
|
+
name: "suggestcat",
|
|
364
|
+
addProseMirrorPlugins() {
|
|
365
|
+
return [
|
|
366
|
+
grammarSuggestPluginV2("<YOUR_API_KEY>"),
|
|
367
|
+
completePluginV2("<YOUR_API_KEY>"),
|
|
368
|
+
autoCompletePlugin("<YOUR_API_KEY>"),
|
|
369
|
+
];
|
|
370
|
+
},
|
|
371
|
+
});
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
## React UI
|
|
375
|
+
|
|
376
|
+
For a ready-made React UI with a slash menu, suggestion overlay and "Ask AI" tooltip, see [prosemirror-suggestcat-plugin-react](https://github.com/emergence-engineering/prosemirror-suggestcat-plugin-react).
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ApiConfig } from "./types";
|
|
2
|
+
export declare const DEFAULT_COMPLETION_ENDPOINT = "https://suggestion-gw5lxik4dq-uc.a.run.app";
|
|
3
|
+
export declare const DEFAULT_GRAMMAR_ENDPOINT = "https://prosemirror-ai-plugin.web.app/api/suggestion";
|
|
4
|
+
export declare const DEFAULT_MODEL = "openai:gpt-4o-mini";
|
|
5
|
+
export type AIModel = "openai:gpt-4o" | "openai:gpt-4o-mini" | "cerebras:llama-3.1-8b" | "cerebras:llama-3.3-70b" | "cerebras:qwen-3-32b";
|
|
6
|
+
export declare function createApiConfig(config: ApiConfig): Required<ApiConfig>;
|
|
7
|
+
export declare function createGrammarApiConfig(config: ApiConfig): Required<ApiConfig>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { DEFAULT_COMPLETION_ENDPOINT, DEFAULT_GRAMMAR_ENDPOINT, DEFAULT_MODEL, createApiConfig, createGrammarApiConfig, } from "./config";
|
|
2
|
+
export type { ApiConfig, ApiRequestBody, StreamingCallbacks, GrammarApiResponse, } from "./types";
|
|
3
|
+
export { streamingRequest, type StreamingRequestOptions } from "./streaming";
|
|
4
|
+
export { grammarRequest, type GrammarRequestOptions, type GrammarRequestResult, } from "./request";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface GrammarRequestOptions {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
text: string;
|
|
4
|
+
endpoint?: string;
|
|
5
|
+
model?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface GrammarRequestResult {
|
|
8
|
+
result: string;
|
|
9
|
+
fixed: boolean;
|
|
10
|
+
error?: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Make a non-streaming request to the grammar API.
|
|
14
|
+
* Returns the corrected text.
|
|
15
|
+
*/
|
|
16
|
+
export declare function grammarRequest(options: GrammarRequestOptions): Promise<GrammarRequestResult>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { TaskType, TaskParams } from "../types";
|
|
2
|
+
import type { StreamingCallbacks } from "./types";
|
|
3
|
+
export interface StreamingRequestOptions {
|
|
4
|
+
apiKey: string;
|
|
5
|
+
text: string;
|
|
6
|
+
task: TaskType;
|
|
7
|
+
params?: TaskParams;
|
|
8
|
+
endpoint?: string;
|
|
9
|
+
model?: string;
|
|
10
|
+
signal?: AbortSignal;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Make a streaming request to the AI API.
|
|
14
|
+
* Returns a promise that resolves when the stream completes.
|
|
15
|
+
*/
|
|
16
|
+
export declare function streamingRequest(options: StreamingRequestOptions, callbacks: StreamingCallbacks): Promise<void>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { TaskType, TaskParams } from "../types";
|
|
2
|
+
import { AIModel } from "./config";
|
|
3
|
+
export interface ApiConfig {
|
|
4
|
+
apiKey: string;
|
|
5
|
+
endpoint?: string;
|
|
6
|
+
model?: string | AIModel;
|
|
7
|
+
}
|
|
8
|
+
export interface ApiRequestBody {
|
|
9
|
+
model: string;
|
|
10
|
+
modelParams: {
|
|
11
|
+
input: string[];
|
|
12
|
+
task?: TaskType;
|
|
13
|
+
params?: TaskParams;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export interface StreamingCallbacks {
|
|
17
|
+
onChunk: (chunk: string, accumulated: string) => void;
|
|
18
|
+
onComplete: (result: string) => void;
|
|
19
|
+
onError: (error: Error) => void;
|
|
20
|
+
}
|
|
21
|
+
export interface GrammarApiResponse {
|
|
22
|
+
result: string;
|
|
23
|
+
fixed: boolean;
|
|
24
|
+
mod?: {
|
|
25
|
+
original: string;
|
|
26
|
+
fixed: string;
|
|
27
|
+
position: number;
|
|
28
|
+
type: string;
|
|
29
|
+
}[];
|
|
30
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public action functions for the auto-complete plugin
|
|
3
|
+
*
|
|
4
|
+
* These functions provide a clean API for controlling the plugin
|
|
5
|
+
* from outside (e.g., from React components or other plugins).
|
|
6
|
+
*/
|
|
7
|
+
import { EditorView } from "prosemirror-view";
|
|
8
|
+
import { AutoCompleteState } from "./types";
|
|
9
|
+
/**
|
|
10
|
+
* Enable or disable the auto-complete plugin
|
|
11
|
+
*/
|
|
12
|
+
export declare function setAutoCompleteEnabled(view: EditorView, enabled: boolean): void;
|
|
13
|
+
/**
|
|
14
|
+
* Accept the current completion (if showing)
|
|
15
|
+
* This is typically triggered by pressing Tab, but can be called programmatically
|
|
16
|
+
*/
|
|
17
|
+
export declare function acceptAutoCompletion(view: EditorView): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Dismiss the current completion without accepting it
|
|
20
|
+
*/
|
|
21
|
+
export declare function dismissAutoCompletion(view: EditorView): void;
|
|
22
|
+
/**
|
|
23
|
+
* Get the current auto-complete plugin state
|
|
24
|
+
*/
|
|
25
|
+
export declare function getAutoCompleteState(view: EditorView): AutoCompleteState | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Check if auto-complete is currently enabled
|
|
28
|
+
*/
|
|
29
|
+
export declare function isAutoCompleteEnabled(view: EditorView): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Check if a completion is currently being shown
|
|
32
|
+
*/
|
|
33
|
+
export declare function hasAutoCompletion(view: EditorView): boolean;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-complete plugin module
|
|
3
|
+
*
|
|
4
|
+
* Shows AI-powered inline completion suggestions as ghost text
|
|
5
|
+
* after the user stops typing.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { autoCompletePlugin, setAutoCompleteEnabled } from 'prosemirror-suggestcat-plugin';
|
|
10
|
+
*
|
|
11
|
+
* const plugins = [
|
|
12
|
+
* autoCompletePlugin('your-api-key', {
|
|
13
|
+
* debounceMs: 500,
|
|
14
|
+
* maxContextLength: 2000,
|
|
15
|
+
* }),
|
|
16
|
+
* // ... other plugins
|
|
17
|
+
* ];
|
|
18
|
+
*
|
|
19
|
+
* // To toggle the plugin:
|
|
20
|
+
* setAutoCompleteEnabled(view, false);
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* CSS for ghost text (user responsibility):
|
|
24
|
+
* ```css
|
|
25
|
+
* .autoCompleteGhostText {
|
|
26
|
+
* color: #9ca3af;
|
|
27
|
+
* opacity: 0.7;
|
|
28
|
+
* pointer-events: none;
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export { AutoCompleteStatus, AutoCompleteActionType, type AutoCompleteState, type AutoCompleteAction, type AutoCompleteOptions, type AutoCompleteSetEnabledAction, type AutoCompleteStartDebounceAction, type AutoCompleteStartRequestAction, type AutoCompleteStreamUpdateAction, type AutoCompleteStreamCompleteAction, type AutoCompleteStreamErrorAction, type AutoCompleteDismissAction, type AutoCompleteAcceptAction, defaultAutoCompleteOptions, } from "./types";
|
|
33
|
+
export { autoCompletePlugin, autoCompleteKey } from "./plugin";
|
|
34
|
+
export { setAutoCompleteEnabled, acceptAutoCompletion, dismissAutoCompletion, getAutoCompleteState, isAutoCompleteEnabled, hasAutoCompletion, } from "./actions";
|
|
35
|
+
export { cancelActiveRequest as cancelAutoCompleteRequest, hasActiveRequest as hasAutoCompleteRequest, } from "./streaming";
|