@milkdown/crepe 7.20.0 → 7.21.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/lib/cjs/builder.js +1 -0
- package/lib/cjs/builder.js.map +1 -1
- package/lib/cjs/feature/ai/index.js +1492 -0
- package/lib/cjs/feature/ai/index.js.map +1 -0
- package/lib/cjs/feature/block-edit/index.js +1 -0
- package/lib/cjs/feature/block-edit/index.js.map +1 -1
- package/lib/cjs/feature/code-mirror/index.js +1 -0
- package/lib/cjs/feature/code-mirror/index.js.map +1 -1
- package/lib/cjs/feature/cursor/index.js +1 -0
- package/lib/cjs/feature/cursor/index.js.map +1 -1
- package/lib/cjs/feature/image-block/index.js +1 -0
- package/lib/cjs/feature/image-block/index.js.map +1 -1
- package/lib/cjs/feature/latex/index.js +2 -0
- package/lib/cjs/feature/latex/index.js.map +1 -1
- package/lib/cjs/feature/link-tooltip/index.js +1 -0
- package/lib/cjs/feature/link-tooltip/index.js.map +1 -1
- package/lib/cjs/feature/list-item/index.js +1 -0
- package/lib/cjs/feature/list-item/index.js.map +1 -1
- package/lib/cjs/feature/placeholder/index.js +1 -0
- package/lib/cjs/feature/placeholder/index.js.map +1 -1
- package/lib/cjs/feature/table/index.js +1 -0
- package/lib/cjs/feature/table/index.js.map +1 -1
- package/lib/cjs/feature/toolbar/index.js +488 -3
- package/lib/cjs/feature/toolbar/index.js.map +1 -1
- package/lib/cjs/feature/top-bar/index.js +1 -0
- package/lib/cjs/feature/top-bar/index.js.map +1 -1
- package/lib/cjs/index.js +1424 -25
- package/lib/cjs/index.js.map +1 -1
- package/lib/cjs/llm-providers/anthropic/index.js +147 -0
- package/lib/cjs/llm-providers/anthropic/index.js.map +1 -0
- package/lib/cjs/llm-providers/openai/index.js +138 -0
- package/lib/cjs/llm-providers/openai/index.js.map +1 -0
- package/lib/esm/builder.js +1 -0
- package/lib/esm/builder.js.map +1 -1
- package/lib/esm/feature/ai/index.js +1487 -0
- package/lib/esm/feature/ai/index.js.map +1 -0
- package/lib/esm/feature/block-edit/index.js +1 -0
- package/lib/esm/feature/block-edit/index.js.map +1 -1
- package/lib/esm/feature/code-mirror/index.js +1 -0
- package/lib/esm/feature/code-mirror/index.js.map +1 -1
- package/lib/esm/feature/cursor/index.js +1 -0
- package/lib/esm/feature/cursor/index.js.map +1 -1
- package/lib/esm/feature/image-block/index.js +1 -0
- package/lib/esm/feature/image-block/index.js.map +1 -1
- package/lib/esm/feature/latex/index.js +2 -0
- package/lib/esm/feature/latex/index.js.map +1 -1
- package/lib/esm/feature/link-tooltip/index.js +1 -0
- package/lib/esm/feature/link-tooltip/index.js.map +1 -1
- package/lib/esm/feature/list-item/index.js +1 -0
- package/lib/esm/feature/list-item/index.js.map +1 -1
- package/lib/esm/feature/placeholder/index.js +1 -0
- package/lib/esm/feature/placeholder/index.js.map +1 -1
- package/lib/esm/feature/table/index.js +1 -0
- package/lib/esm/feature/table/index.js.map +1 -1
- package/lib/esm/feature/toolbar/index.js +490 -5
- package/lib/esm/feature/toolbar/index.js.map +1 -1
- package/lib/esm/feature/top-bar/index.js +1 -0
- package/lib/esm/feature/top-bar/index.js.map +1 -1
- package/lib/esm/index.js +1414 -15
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/llm-providers/anthropic/index.js +145 -0
- package/lib/esm/llm-providers/anthropic/index.js.map +1 -0
- package/lib/esm/llm-providers/openai/index.js +136 -0
- package/lib/esm/llm-providers/openai/index.js.map +1 -0
- package/lib/theme/common/ai.css +446 -0
- package/lib/theme/common/code-mirror.css +14 -0
- package/lib/theme/common/diff.css +177 -0
- package/lib/theme/common/style.css +2 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/types/feature/ai/ai.spec.d.ts +2 -0
- package/lib/types/feature/ai/ai.spec.d.ts.map +1 -0
- package/lib/types/feature/ai/commands.d.ts +24 -0
- package/lib/types/feature/ai/commands.d.ts.map +1 -0
- package/lib/types/feature/ai/context.d.ts +4 -0
- package/lib/types/feature/ai/context.d.ts.map +1 -0
- package/lib/types/feature/ai/diff-actions/index.d.ts +12 -0
- package/lib/types/feature/ai/diff-actions/index.d.ts.map +1 -0
- package/lib/types/feature/ai/diff-actions/view.d.ts +21 -0
- package/lib/types/feature/ai/diff-actions/view.d.ts.map +1 -0
- package/lib/types/feature/ai/index.d.ts +7 -0
- package/lib/types/feature/ai/index.d.ts.map +1 -0
- package/lib/types/feature/ai/instruction-tooltip/component.d.ts +26 -0
- package/lib/types/feature/ai/instruction-tooltip/component.d.ts.map +1 -0
- package/lib/types/feature/ai/instruction-tooltip/index.d.ts +17 -0
- package/lib/types/feature/ai/instruction-tooltip/index.d.ts.map +1 -0
- package/lib/types/feature/ai/instruction-tooltip/suggestions.d.ts +50 -0
- package/lib/types/feature/ai/instruction-tooltip/suggestions.d.ts.map +1 -0
- package/lib/types/feature/ai/instruction-tooltip/view.d.ts +19 -0
- package/lib/types/feature/ai/instruction-tooltip/view.d.ts.map +1 -0
- package/lib/types/feature/ai/streaming-indicator.d.ts +9 -0
- package/lib/types/feature/ai/streaming-indicator.d.ts.map +1 -0
- package/lib/types/feature/ai/types.d.ts +58 -0
- package/lib/types/feature/ai/types.d.ts.map +1 -0
- package/lib/types/feature/index.d.ts +4 -1
- package/lib/types/feature/index.d.ts.map +1 -1
- package/lib/types/feature/latex/inline-tooltip/inline-tooltip.spec.d.ts +2 -0
- package/lib/types/feature/latex/inline-tooltip/inline-tooltip.spec.d.ts.map +1 -0
- package/lib/types/feature/latex/inline-tooltip/view.d.ts.map +1 -1
- package/lib/types/feature/loader.d.ts.map +1 -1
- package/lib/types/feature/toolbar/config.d.ts.map +1 -1
- package/lib/types/feature/toolbar/index.d.ts +1 -0
- package/lib/types/feature/toolbar/index.d.ts.map +1 -1
- package/lib/types/icons/ai.d.ts +2 -0
- package/lib/types/icons/ai.d.ts.map +1 -0
- package/lib/types/icons/chevron-left.d.ts +2 -0
- package/lib/types/icons/chevron-left.d.ts.map +1 -0
- package/lib/types/icons/chevron-right.d.ts +2 -0
- package/lib/types/icons/chevron-right.d.ts.map +1 -0
- package/lib/types/icons/enter-key.d.ts +2 -0
- package/lib/types/icons/enter-key.d.ts.map +1 -0
- package/lib/types/icons/grammar-check.d.ts +2 -0
- package/lib/types/icons/grammar-check.d.ts.map +1 -0
- package/lib/types/icons/index.d.ts +11 -0
- package/lib/types/icons/index.d.ts.map +1 -1
- package/lib/types/icons/longer.d.ts +2 -0
- package/lib/types/icons/longer.d.ts.map +1 -0
- package/lib/types/icons/retry.d.ts +2 -0
- package/lib/types/icons/retry.d.ts.map +1 -0
- package/lib/types/icons/send-prompt.d.ts +2 -0
- package/lib/types/icons/send-prompt.d.ts.map +1 -0
- package/lib/types/icons/send.d.ts +2 -0
- package/lib/types/icons/send.d.ts.map +1 -0
- package/lib/types/icons/shorter.d.ts +2 -0
- package/lib/types/icons/shorter.d.ts.map +1 -0
- package/lib/types/icons/translate.d.ts +2 -0
- package/lib/types/icons/translate.d.ts.map +1 -0
- package/lib/types/llm-providers/anthropic/index.d.ts +21 -0
- package/lib/types/llm-providers/anthropic/index.d.ts.map +1 -0
- package/lib/types/llm-providers/openai/index.d.ts +15 -0
- package/lib/types/llm-providers/openai/index.d.ts.map +1 -0
- package/lib/types/llm-providers/providers.spec.d.ts +2 -0
- package/lib/types/llm-providers/providers.spec.d.ts.map +1 -0
- package/lib/types/llm-providers/shared.d.ts +16 -0
- package/lib/types/llm-providers/shared.d.ts.map +1 -0
- package/package.json +18 -2
- package/src/feature/ai/ai.spec.ts +742 -0
- package/src/feature/ai/commands.ts +257 -0
- package/src/feature/ai/context.ts +45 -0
- package/src/feature/ai/diff-actions/index.ts +95 -0
- package/src/feature/ai/diff-actions/view.ts +237 -0
- package/src/feature/ai/index.ts +118 -0
- package/src/feature/ai/instruction-tooltip/component.tsx +414 -0
- package/src/feature/ai/instruction-tooltip/index.ts +101 -0
- package/src/feature/ai/instruction-tooltip/suggestions.ts +249 -0
- package/src/feature/ai/instruction-tooltip/view.ts +159 -0
- package/src/feature/ai/streaming-indicator.ts +183 -0
- package/src/feature/ai/types.ts +178 -0
- package/src/feature/index.ts +8 -2
- package/src/feature/latex/inline-tooltip/inline-tooltip.spec.ts +81 -0
- package/src/feature/latex/inline-tooltip/view.ts +2 -0
- package/src/feature/loader.ts +4 -0
- package/src/feature/toolbar/config.ts +27 -1
- package/src/feature/toolbar/index.ts +1 -0
- package/src/icons/ai.ts +14 -0
- package/src/icons/chevron-left.ts +15 -0
- package/src/icons/chevron-right.ts +15 -0
- package/src/icons/enter-key.ts +13 -0
- package/src/icons/grammar-check.ts +13 -0
- package/src/icons/index.ts +11 -0
- package/src/icons/longer.ts +13 -0
- package/src/icons/retry.ts +13 -0
- package/src/icons/send-prompt.ts +13 -0
- package/src/icons/send.ts +13 -0
- package/src/icons/shorter.ts +13 -0
- package/src/icons/translate.ts +13 -0
- package/src/llm-providers/anthropic/index.ts +132 -0
- package/src/llm-providers/openai/index.ts +109 -0
- package/src/llm-providers/providers.spec.ts +472 -0
- package/src/llm-providers/shared.ts +160 -0
- package/src/theme/common/ai.css +430 -0
- package/src/theme/common/code-mirror.css +14 -0
- package/src/theme/common/diff.css +196 -0
- package/src/theme/common/style.css +2 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { AIPromptContext, AIProvider } from '../../feature/ai/types'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
type BaseProviderConfig,
|
|
5
|
+
assertBrowserSafe,
|
|
6
|
+
buildDefaultUserMessage,
|
|
7
|
+
parseSSE,
|
|
8
|
+
readErrorBody,
|
|
9
|
+
resolveSystemPrompt,
|
|
10
|
+
} from '../shared'
|
|
11
|
+
|
|
12
|
+
const PROVIDER_NAME = 'milkdown/providers/anthropic'
|
|
13
|
+
const DEFAULT_BASE_URL = 'https://api.anthropic.com'
|
|
14
|
+
const DEFAULT_ANTHROPIC_VERSION = '2023-06-01'
|
|
15
|
+
const DEFAULT_MAX_TOKENS = 4096
|
|
16
|
+
|
|
17
|
+
export interface AnthropicMessage {
|
|
18
|
+
role: 'user' | 'assistant'
|
|
19
|
+
content: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface AnthropicBuildMessagesResult {
|
|
23
|
+
/// Anthropic puts the system prompt in a top-level `system` field,
|
|
24
|
+
/// not in the messages array.
|
|
25
|
+
system?: string
|
|
26
|
+
messages: AnthropicMessage[]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface AnthropicProviderConfig extends BaseProviderConfig {
|
|
30
|
+
/// Anthropic's API requires `max_tokens`. Defaults to 4096.
|
|
31
|
+
maxTokens?: number
|
|
32
|
+
|
|
33
|
+
/// `anthropic-version` header. Defaults to `2023-06-01`.
|
|
34
|
+
anthropicVersion?: string
|
|
35
|
+
|
|
36
|
+
/// Customize the request payload. The default builder maps the
|
|
37
|
+
/// resolved system prompt to `system` and produces a single user
|
|
38
|
+
/// message containing the document, selection, and instruction.
|
|
39
|
+
buildMessages?: (
|
|
40
|
+
context: AIPromptContext,
|
|
41
|
+
defaults: { systemPrompt: string | null; userMessage: string }
|
|
42
|
+
) => AnthropicBuildMessagesResult
|
|
43
|
+
|
|
44
|
+
/// Extra fields merged into the request body (e.g. `temperature`,
|
|
45
|
+
/// `top_p`, `metadata`, `tool_choice`).
|
|
46
|
+
body?: Record<string, unknown>
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface AnthropicStreamEvent {
|
|
50
|
+
type: string
|
|
51
|
+
delta?: {
|
|
52
|
+
type?: string
|
|
53
|
+
text?: string
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/// Build an `AIProvider` backed by Anthropic's `/v1/messages` streaming
|
|
58
|
+
/// endpoint. The returned function plugs directly into
|
|
59
|
+
/// `Crepe.Feature.AI`'s `provider` field.
|
|
60
|
+
export function createAnthropicProvider(
|
|
61
|
+
config: AnthropicProviderConfig
|
|
62
|
+
): AIProvider {
|
|
63
|
+
assertBrowserSafe(config, PROVIDER_NAME)
|
|
64
|
+
|
|
65
|
+
return async function* anthropicProvider(context, signal) {
|
|
66
|
+
const systemPrompt = resolveSystemPrompt(config.systemPrompt)
|
|
67
|
+
const userMessage = buildDefaultUserMessage(context)
|
|
68
|
+
|
|
69
|
+
const built = config.buildMessages
|
|
70
|
+
? config.buildMessages(context, { systemPrompt, userMessage })
|
|
71
|
+
: {
|
|
72
|
+
system: systemPrompt ?? undefined,
|
|
73
|
+
messages: [
|
|
74
|
+
{ role: 'user' as const, content: userMessage },
|
|
75
|
+
] satisfies AnthropicMessage[],
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const baseURL = (config.baseURL ?? DEFAULT_BASE_URL).replace(/\/+$/, '')
|
|
79
|
+
const url = `${baseURL}/v1/messages`
|
|
80
|
+
|
|
81
|
+
const headers: Record<string, string> = {
|
|
82
|
+
'Content-Type': 'application/json',
|
|
83
|
+
'anthropic-version': config.anthropicVersion ?? DEFAULT_ANTHROPIC_VERSION,
|
|
84
|
+
...(config.apiKey ? { 'x-api-key': config.apiKey } : {}),
|
|
85
|
+
// Required for direct browser → api.anthropic.com calls; harmless
|
|
86
|
+
// when proxying through a backend.
|
|
87
|
+
...(config.dangerouslyAllowBrowser
|
|
88
|
+
? { 'anthropic-dangerous-direct-browser-access': 'true' }
|
|
89
|
+
: {}),
|
|
90
|
+
...config.headers,
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const body = JSON.stringify({
|
|
94
|
+
model: config.model,
|
|
95
|
+
max_tokens: config.maxTokens ?? DEFAULT_MAX_TOKENS,
|
|
96
|
+
stream: true,
|
|
97
|
+
// Caller-supplied empty string is still a value; only `undefined`
|
|
98
|
+
// (i.e. resolveSystemPrompt returned `null`) means "omit".
|
|
99
|
+
...(built.system !== undefined ? { system: built.system } : {}),
|
|
100
|
+
messages: built.messages,
|
|
101
|
+
...config.body,
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
const response = await fetch(url, {
|
|
105
|
+
method: 'POST',
|
|
106
|
+
headers,
|
|
107
|
+
body,
|
|
108
|
+
signal,
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
if (!response.ok) {
|
|
112
|
+
throw await readErrorBody(response, PROVIDER_NAME)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
for await (const payload of parseSSE(response, signal)) {
|
|
116
|
+
let event: AnthropicStreamEvent
|
|
117
|
+
try {
|
|
118
|
+
event = JSON.parse(payload) as AnthropicStreamEvent
|
|
119
|
+
} catch {
|
|
120
|
+
continue
|
|
121
|
+
}
|
|
122
|
+
if (
|
|
123
|
+
event.type === 'content_block_delta' &&
|
|
124
|
+
event.delta?.type === 'text_delta' &&
|
|
125
|
+
event.delta.text
|
|
126
|
+
) {
|
|
127
|
+
yield event.delta.text
|
|
128
|
+
}
|
|
129
|
+
if (event.type === 'message_stop') return
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { AIPromptContext, AIProvider } from '../../feature/ai/types'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
type BaseProviderConfig,
|
|
5
|
+
assertBrowserSafe,
|
|
6
|
+
buildDefaultUserMessage,
|
|
7
|
+
parseSSE,
|
|
8
|
+
readErrorBody,
|
|
9
|
+
resolveSystemPrompt,
|
|
10
|
+
} from '../shared'
|
|
11
|
+
|
|
12
|
+
const PROVIDER_NAME = 'milkdown/providers/openai'
|
|
13
|
+
const DEFAULT_BASE_URL = 'https://api.openai.com'
|
|
14
|
+
|
|
15
|
+
export interface OpenAIChatMessage {
|
|
16
|
+
role: 'system' | 'user' | 'assistant'
|
|
17
|
+
content: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface OpenAIProviderConfig extends BaseProviderConfig {
|
|
21
|
+
/// Customize the messages sent to `/v1/chat/completions`. The default
|
|
22
|
+
/// builder produces a system message (when not disabled) followed by
|
|
23
|
+
/// a structured user message containing the document, selection, and
|
|
24
|
+
/// instruction. The defaults are passed in so callers can wrap them
|
|
25
|
+
/// rather than re-deriving from scratch.
|
|
26
|
+
buildMessages?: (
|
|
27
|
+
context: AIPromptContext,
|
|
28
|
+
defaults: { systemPrompt: string | null; userMessage: string }
|
|
29
|
+
) => OpenAIChatMessage[]
|
|
30
|
+
|
|
31
|
+
/// Extra fields merged into the request body (e.g. `temperature`,
|
|
32
|
+
/// `top_p`, `presence_penalty`, `response_format`).
|
|
33
|
+
body?: Record<string, unknown>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface OpenAIStreamChunk {
|
|
37
|
+
choices?: Array<{
|
|
38
|
+
delta?: { content?: string }
|
|
39
|
+
finish_reason?: string | null
|
|
40
|
+
}>
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/// Build an `AIProvider` backed by OpenAI's `/v1/chat/completions`
|
|
44
|
+
/// streaming endpoint. The returned function plugs directly into
|
|
45
|
+
/// `Crepe.Feature.AI`'s `provider` field.
|
|
46
|
+
export function createOpenAIProvider(config: OpenAIProviderConfig): AIProvider {
|
|
47
|
+
assertBrowserSafe(config, PROVIDER_NAME)
|
|
48
|
+
|
|
49
|
+
return async function* openAIProvider(context, signal) {
|
|
50
|
+
const systemPrompt = resolveSystemPrompt(config.systemPrompt)
|
|
51
|
+
const userMessage = buildDefaultUserMessage(context)
|
|
52
|
+
|
|
53
|
+
const messages = config.buildMessages
|
|
54
|
+
? config.buildMessages(context, { systemPrompt, userMessage })
|
|
55
|
+
: defaultMessages(systemPrompt, userMessage)
|
|
56
|
+
|
|
57
|
+
const baseURL = (config.baseURL ?? DEFAULT_BASE_URL).replace(/\/+$/, '')
|
|
58
|
+
const url = `${baseURL}/v1/chat/completions`
|
|
59
|
+
|
|
60
|
+
const headers: Record<string, string> = {
|
|
61
|
+
'Content-Type': 'application/json',
|
|
62
|
+
...(config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}),
|
|
63
|
+
...config.headers,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const body = JSON.stringify({
|
|
67
|
+
model: config.model,
|
|
68
|
+
stream: true,
|
|
69
|
+
messages,
|
|
70
|
+
...config.body,
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
const response = await fetch(url, {
|
|
74
|
+
method: 'POST',
|
|
75
|
+
headers,
|
|
76
|
+
body,
|
|
77
|
+
signal,
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
if (!response.ok) {
|
|
81
|
+
throw await readErrorBody(response, PROVIDER_NAME)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
for await (const payload of parseSSE(response, signal)) {
|
|
85
|
+
if (payload === '[DONE]') return
|
|
86
|
+
let event: OpenAIStreamChunk
|
|
87
|
+
try {
|
|
88
|
+
event = JSON.parse(payload) as OpenAIStreamChunk
|
|
89
|
+
} catch {
|
|
90
|
+
continue
|
|
91
|
+
}
|
|
92
|
+
const delta = event.choices?.[0]?.delta?.content
|
|
93
|
+
if (delta) yield delta
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function defaultMessages(
|
|
99
|
+
systemPrompt: string | null,
|
|
100
|
+
userMessage: string
|
|
101
|
+
): OpenAIChatMessage[] {
|
|
102
|
+
const messages: OpenAIChatMessage[] = []
|
|
103
|
+
// `null` means "omit"; an empty string is still a caller-provided
|
|
104
|
+
// value and should be sent as-is.
|
|
105
|
+
if (systemPrompt !== null)
|
|
106
|
+
messages.push({ role: 'system', content: systemPrompt })
|
|
107
|
+
messages.push({ role: 'user', content: userMessage })
|
|
108
|
+
return messages
|
|
109
|
+
}
|