@milkdown/crepe 7.20.0 → 7.21.1

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