@milkdown/crepe 7.19.2 → 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 +44 -1
- 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 +9 -2
- package/lib/cjs/feature/block-edit/index.js.map +1 -1
- package/lib/cjs/feature/code-mirror/index.js +2 -0
- package/lib/cjs/feature/code-mirror/index.js.map +1 -1
- package/lib/cjs/feature/cursor/index.js +2 -0
- package/lib/cjs/feature/cursor/index.js.map +1 -1
- package/lib/cjs/feature/image-block/index.js +5 -1
- package/lib/cjs/feature/image-block/index.js.map +1 -1
- package/lib/cjs/feature/latex/index.js +7 -0
- package/lib/cjs/feature/latex/index.js.map +1 -1
- package/lib/cjs/feature/link-tooltip/index.js +2 -0
- package/lib/cjs/feature/link-tooltip/index.js.map +1 -1
- package/lib/cjs/feature/list-item/index.js +2 -0
- package/lib/cjs/feature/list-item/index.js.map +1 -1
- package/lib/cjs/feature/placeholder/index.js +2 -0
- package/lib/cjs/feature/placeholder/index.js.map +1 -1
- package/lib/cjs/feature/table/index.js +2 -0
- package/lib/cjs/feature/table/index.js.map +1 -1
- package/lib/cjs/feature/toolbar/index.js +497 -5
- package/lib/cjs/feature/toolbar/index.js.map +1 -1
- package/lib/cjs/feature/top-bar/index.js +791 -0
- package/lib/cjs/feature/top-bar/index.js.map +1 -0
- package/lib/cjs/index.js +2047 -160
- 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 +44 -1
- 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 +9 -2
- package/lib/esm/feature/block-edit/index.js.map +1 -1
- package/lib/esm/feature/code-mirror/index.js +2 -0
- package/lib/esm/feature/code-mirror/index.js.map +1 -1
- package/lib/esm/feature/cursor/index.js +2 -0
- package/lib/esm/feature/cursor/index.js.map +1 -1
- package/lib/esm/feature/image-block/index.js +5 -1
- package/lib/esm/feature/image-block/index.js.map +1 -1
- package/lib/esm/feature/latex/index.js +7 -0
- package/lib/esm/feature/latex/index.js.map +1 -1
- package/lib/esm/feature/link-tooltip/index.js +2 -0
- package/lib/esm/feature/link-tooltip/index.js.map +1 -1
- package/lib/esm/feature/list-item/index.js +2 -0
- package/lib/esm/feature/list-item/index.js.map +1 -1
- package/lib/esm/feature/placeholder/index.js +2 -0
- package/lib/esm/feature/placeholder/index.js.map +1 -1
- package/lib/esm/feature/table/index.js +2 -0
- package/lib/esm/feature/table/index.js.map +1 -1
- package/lib/esm/feature/toolbar/index.js +499 -7
- package/lib/esm/feature/toolbar/index.js.map +1 -1
- package/lib/esm/feature/top-bar/index.js +789 -0
- package/lib/esm/feature/top-bar/index.js.map +1 -0
- package/lib/esm/index.js +2040 -153
- 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 +3 -0
- package/lib/theme/common/top-bar.css +152 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/types/core/builder.d.ts +2 -1
- package/lib/types/core/builder.d.ts.map +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/block-edit/handle/component.d.ts.map +1 -1
- package/lib/types/feature/block-edit/menu/component.d.ts.map +1 -1
- package/lib/types/feature/image-block/index.d.ts +2 -0
- package/lib/types/feature/image-block/index.d.ts.map +1 -1
- package/lib/types/feature/index.d.ts +7 -1
- package/lib/types/feature/index.d.ts.map +1 -1
- package/lib/types/feature/latex/inline-tooltip/component.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/component.d.ts.map +1 -1
- package/lib/types/feature/toolbar/config.d.ts +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/feature/top-bar/component.d.ts +11 -0
- package/lib/types/feature/top-bar/component.d.ts.map +1 -0
- package/lib/types/feature/top-bar/config.d.ts +34 -0
- package/lib/types/feature/top-bar/config.d.ts.map +1 -0
- package/lib/types/feature/top-bar/index.d.ts +26 -0
- package/lib/types/feature/top-bar/index.d.ts.map +1 -0
- 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/code-block.d.ts +2 -0
- package/lib/types/icons/code-block.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 +12 -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/lib/types/utils/group-builder.d.ts +1 -1
- package/lib/types/utils/group-builder.d.ts.map +1 -1
- package/lib/types/utils/keep-alive.d.ts +2 -0
- package/lib/types/utils/keep-alive.d.ts.map +1 -0
- package/package.json +34 -13
- package/src/core/builder.ts +39 -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/block-edit/handle/component.tsx +3 -2
- package/src/feature/block-edit/menu/component.tsx +3 -2
- package/src/feature/block-edit/menu/config.ts +1 -1
- package/src/feature/image-block/index.ts +4 -0
- package/src/feature/index.ts +14 -2
- package/src/feature/latex/inline-tooltip/component.tsx +4 -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 +8 -0
- package/src/feature/toolbar/component.tsx +7 -5
- package/src/feature/toolbar/config.ts +27 -1
- package/src/feature/toolbar/index.ts +1 -0
- package/src/feature/top-bar/component.tsx +198 -0
- package/src/feature/top-bar/config.ts +367 -0
- package/src/feature/top-bar/index.ts +113 -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/code-block.ts +12 -0
- package/src/icons/enter-key.ts +13 -0
- package/src/icons/grammar-check.ts +13 -0
- package/src/icons/index.ts +12 -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 +3 -0
- package/src/theme/common/top-bar.css +156 -0
- package/src/utils/group-builder.ts +1 -1
- package/src/utils/keep-alive.ts +3 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const chevronRightIcon = `
|
|
2
|
+
<svg
|
|
3
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
4
|
+
fill="none"
|
|
5
|
+
viewBox="0 0 24 24"
|
|
6
|
+
stroke-width="1.5"
|
|
7
|
+
stroke="currentColor"
|
|
8
|
+
>
|
|
9
|
+
<path
|
|
10
|
+
stroke-linecap="round"
|
|
11
|
+
stroke-linejoin="round"
|
|
12
|
+
d="M8.25 4.5l7.5 7.5-7.5 7.5"
|
|
13
|
+
/>
|
|
14
|
+
</svg>
|
|
15
|
+
`
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const codeBlockIcon = `
|
|
2
|
+
<svg
|
|
3
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
4
|
+
width="24"
|
|
5
|
+
height="24"
|
|
6
|
+
viewBox="0 0 24 24"
|
|
7
|
+
>
|
|
8
|
+
<path
|
|
9
|
+
d="M3 3h18a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1zm1 2v14h16V5H4zm8 10h6v2h-6v-2zm-3.333-3L5.838 9.172l1.415-1.415L11.495 12l-4.242 4.243-1.415-1.415L8.667 12z"
|
|
10
|
+
/>
|
|
11
|
+
</svg>
|
|
12
|
+
`
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const grammarCheckIcon = `
|
|
2
|
+
<svg
|
|
3
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
4
|
+
width="24"
|
|
5
|
+
height="24"
|
|
6
|
+
viewBox="0 0 24 24"
|
|
7
|
+
>
|
|
8
|
+
<path
|
|
9
|
+
fill="currentColor"
|
|
10
|
+
d="M9.55 17.575L4.225 12.25l1.4-1.425L9.55 14.75l8.825-8.825l1.4 1.425z"
|
|
11
|
+
/>
|
|
12
|
+
</svg>
|
|
13
|
+
`
|
package/src/icons/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export * from './ai'
|
|
1
2
|
export * from './align-center'
|
|
2
3
|
export * from './align-left'
|
|
3
4
|
export * from './align-right'
|
|
@@ -8,13 +9,18 @@ export * from './caption'
|
|
|
8
9
|
export * from './check-box-checked'
|
|
9
10
|
export * from './check-box-unchecked'
|
|
10
11
|
export * from './chevron-down'
|
|
12
|
+
export * from './chevron-left'
|
|
13
|
+
export * from './chevron-right'
|
|
11
14
|
export * from './clear'
|
|
12
15
|
export * from './code'
|
|
16
|
+
export * from './code-block'
|
|
13
17
|
export * from './confirm'
|
|
14
18
|
export * from './copy'
|
|
15
19
|
export * from './divider'
|
|
16
20
|
export * from './drag-handle'
|
|
17
21
|
export * from './edit'
|
|
22
|
+
export * from './enter-key'
|
|
23
|
+
export * from './grammar-check'
|
|
18
24
|
export * from './h1'
|
|
19
25
|
export * from './h2'
|
|
20
26
|
export * from './h3'
|
|
@@ -24,15 +30,21 @@ export * from './h6'
|
|
|
24
30
|
export * from './image'
|
|
25
31
|
export * from './italic'
|
|
26
32
|
export * from './link'
|
|
33
|
+
export * from './longer'
|
|
27
34
|
export * from './menu'
|
|
28
35
|
export * from './ordered-list'
|
|
29
36
|
export * from './plus'
|
|
30
37
|
export * from './quote'
|
|
31
38
|
export * from './remove'
|
|
39
|
+
export * from './retry'
|
|
32
40
|
export * from './search'
|
|
41
|
+
export * from './send'
|
|
42
|
+
export * from './send-prompt'
|
|
43
|
+
export * from './shorter'
|
|
33
44
|
export * from './strikethrough'
|
|
34
45
|
export * from './table'
|
|
35
46
|
export * from './text'
|
|
36
47
|
export * from './todo-list'
|
|
48
|
+
export * from './translate'
|
|
37
49
|
export * from './functions'
|
|
38
50
|
export * from './visibility-off'
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const longerIcon = `
|
|
2
|
+
<svg
|
|
3
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
4
|
+
width="24"
|
|
5
|
+
height="24"
|
|
6
|
+
viewBox="0 0 24 24"
|
|
7
|
+
>
|
|
8
|
+
<path
|
|
9
|
+
fill="currentColor"
|
|
10
|
+
d="M3 18v-2h13v2zm0-5v-2h18v2zm0-5V6h18v2zm15 13v-3h-3v-2h3v-3h2v3h3v2h-3v3z"
|
|
11
|
+
/>
|
|
12
|
+
</svg>
|
|
13
|
+
`
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const retryIcon = `
|
|
2
|
+
<svg
|
|
3
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
4
|
+
width="24"
|
|
5
|
+
height="24"
|
|
6
|
+
viewBox="0 0 24 24"
|
|
7
|
+
>
|
|
8
|
+
<path
|
|
9
|
+
fill="currentColor"
|
|
10
|
+
d="M12 20q-3.35 0-5.675-2.325T4 12q0-3.35 2.325-5.675T12 4q1.725 0 3.3.713T18 6.75V4h2v7h-7V9h4.2q-.8-1.4-2.187-2.2T12 6Q9.5 6 7.75 7.75T6 12q0 2.5 1.75 4.25T12 18q1.925 0 3.475-1.1T17.65 14h2.1q-.7 2.65-2.85 4.325T12 20"
|
|
11
|
+
/>
|
|
12
|
+
</svg>
|
|
13
|
+
`
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const translateIcon = `
|
|
2
|
+
<svg
|
|
3
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
4
|
+
width="24"
|
|
5
|
+
height="24"
|
|
6
|
+
viewBox="0 0 24 24"
|
|
7
|
+
>
|
|
8
|
+
<path
|
|
9
|
+
fill="currentColor"
|
|
10
|
+
d="m12.9 16l-2.55-2.5l.05-.05q1.45-1.6 2.262-3.117T13.95 7H16V5h-6V3H8v2H2v2h9.1q-.5 1.2-1.225 2.387T8 11.7q-.6-.6-1.187-1.412T5.85 8.6H3.85q.5 1.4 1.3 2.7T6.95 13.7L2.85 17.75L4.25 19.15L8 15.4L10.55 17.95zM18.5 22h-2L21 10h2l4.5 12h-2l-1.05-3h-4.9zm1.6-5h3.6l-1.8-5.1z"
|
|
11
|
+
/>
|
|
12
|
+
</svg>
|
|
13
|
+
`
|
|
@@ -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
|
+
}
|