@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.
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 +147 -0
  30. package/lib/cjs/llm-providers/anthropic/index.js.map +1 -0
  31. package/lib/cjs/llm-providers/openai/index.js +138 -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 +145 -0
  62. package/lib/esm/llm-providers/anthropic/index.js.map +1 -0
  63. package/lib/esm/llm-providers/openai/index.js +136 -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 +16 -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 +132 -0
  167. package/src/llm-providers/openai/index.ts +109 -0
  168. package/src/llm-providers/providers.spec.ts +472 -0
  169. package/src/llm-providers/shared.ts +160 -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,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
+ }