@byline/ai 3.0.2 → 3.1.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.
- package/README.md +68 -2
- package/dist/plugins/lexical/commands.d.ts +16 -0
- package/dist/plugins/lexical/commands.d.ts.map +1 -0
- package/dist/plugins/lexical/commands.js +23 -0
- package/dist/plugins/lexical/extension.d.ts.map +1 -1
- package/dist/plugins/lexical/extension.js +21 -4
- package/dist/plugins/lexical/index.d.ts +1 -1
- package/dist/plugins/lexical/index.d.ts.map +1 -1
- package/dist/plugins/lexical/index.js +1 -1
- package/dist/plugins/lexical/plugin.d.ts +0 -8
- package/dist/plugins/lexical/plugin.d.ts.map +1 -1
- package/dist/plugins/lexical/plugin.js +2 -9
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,4 +1,70 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @byline/ai
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The AI subsystem for [Byline CMS](https://github.com/Byline-CMS/bylinecms.dev)
|
|
4
|
+
— provider-agnostic text generation and structured editing for the admin
|
|
5
|
+
editor, with built-in editor plugins for the text and Lexical richtext fields.
|
|
4
6
|
|
|
7
|
+
This package is part of Byline CMS — a developer-friendly, open-source
|
|
8
|
+
headless CMS with versioning, editorial workflow, and content translation as
|
|
9
|
+
first-class concerns.
|
|
10
|
+
|
|
11
|
+
## What it provides
|
|
12
|
+
|
|
13
|
+
- **Provider-agnostic execution** — a single `ExecuteInstruction` contract over
|
|
14
|
+
OpenAI, Google (Gemini), and Anthropic, with non-streaming and streaming
|
|
15
|
+
variants (`executeInstruction` / `executeInstructionStreaming`).
|
|
16
|
+
- **Structured generation** — `generateStructured` / `generateStructuredStreaming`
|
|
17
|
+
for schema-constrained output.
|
|
18
|
+
- **Patch generation** — `patch` / `patchStreaming`, which edit an ordered array
|
|
19
|
+
of Lexical text nodes in place (used by the richtext field's AI drawer).
|
|
20
|
+
- **Editor plugins** — drop-in plugins for the two editor surfaces:
|
|
21
|
+
`@byline/ai/plugins/text` (`AiPluginText`) and `@byline/ai/plugins/lexical`
|
|
22
|
+
(`AiPluginLexical`, `AiLexicalExtension`, `TOGGLE_AI_DRAWER_COMMAND`).
|
|
23
|
+
- **Browser-safe config** — a public config provider and provider/model helpers
|
|
24
|
+
that carry no server SDK dependencies.
|
|
25
|
+
|
|
26
|
+
## Browser / server split
|
|
27
|
+
|
|
28
|
+
The root entry is browser-safe; the SDK-backed execution code lives behind a
|
|
29
|
+
separate server entry. Import from the right one:
|
|
30
|
+
|
|
31
|
+
| Entry | Use from | Surface |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| `@byline/ai` | Browser **and** server | Types, `AiPublicConfigProvider` / `useAiPublicConfig`, provider/model helpers (`PROVIDERS`, `DEFAULT_MODELS`, `getDefaultModel`, …), `INSTRUCTION_MODES` |
|
|
34
|
+
| `@byline/ai/server` | Server only | `executeInstruction(Streaming)`, `generateStructured(Streaming)`, `patch(Streaming)`, `getAiServerConfig` |
|
|
35
|
+
| `@byline/ai/plugins/text` | Browser | `AiPluginText` |
|
|
36
|
+
| `@byline/ai/plugins/lexical` | Browser | `AiPluginLexical`, `AiLexicalExtension`, `TOGGLE_AI_DRAWER_COMMAND` |
|
|
37
|
+
|
|
38
|
+
Importing `@byline/ai/server` in the browser will crash — it pulls in the
|
|
39
|
+
Anthropic/OpenAI/Google SDKs and pino. Host adapters mount the execute endpoint
|
|
40
|
+
on the server and the plugins POST `ExecuteInstruction` payloads to it; see the
|
|
41
|
+
host integration in `@byline/host-tanstack-start` (`integrations/byline-ai.tsx`,
|
|
42
|
+
`server-fns/ai/*`).
|
|
43
|
+
|
|
44
|
+
## Configuration
|
|
45
|
+
|
|
46
|
+
Server config is read from the environment by `getAiServerConfig()`:
|
|
47
|
+
|
|
48
|
+
| Variable | Purpose | Default |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| `AI_DEFAULT_PROVIDER` | `openai` \| `google` \| `anthropic` | `openai` |
|
|
51
|
+
| `OPENAI_API_KEY` / `OPENAI_BASE_URL` | OpenAI credentials | — |
|
|
52
|
+
| `GOOGLE_API_KEY` / `GOOGLE_BASE_URL` | Google (Gemini) credentials | — |
|
|
53
|
+
| `ANTHROPIC_API_KEY` / `ANTHROPIC_BASE_URL` | Anthropic credentials | — |
|
|
54
|
+
| `BYLINE_AI_ENDPOINT` | Endpoint the editor plugins POST to | `/admin/api/ai/execute` |
|
|
55
|
+
| `LOG_LEVEL` / `LOG_PRETTY` | Logging | `info` |
|
|
56
|
+
|
|
57
|
+
The curated per-provider model lists live in `src/config/ai-config.ts`
|
|
58
|
+
(`PROVIDER_MODELS` / `DEFAULT_MODELS`). Run `pnpm list:models` to discover the
|
|
59
|
+
models a provider currently exposes.
|
|
60
|
+
|
|
61
|
+
## Documentation
|
|
62
|
+
|
|
63
|
+
For the full architecture overview, the richtext/AI integration, and getting
|
|
64
|
+
started instructions, see the main repository:
|
|
65
|
+
<https://github.com/Byline-CMS/bylinecms.dev>. Relevant docs: `docs/RICHTEXT.md`,
|
|
66
|
+
`docs/FIELDS.md`, and `docs/MCP.md`.
|
|
67
|
+
|
|
68
|
+
## License
|
|
69
|
+
|
|
70
|
+
MPL-2.0
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
export declare const TOGGLE_AI_DRAWER_COMMAND: import("lexical").LexicalCommand<unknown>;
|
|
9
|
+
/**
|
|
10
|
+
* Broadcasts the AI drawer's open/closed state so contributed UI (the
|
|
11
|
+
* toolbar button) can show an active visual cue. Dispatched by the drawer
|
|
12
|
+
* plugin whenever `open` changes — including closes triggered from the
|
|
13
|
+
* drawer's own controls. Observers register a listener and return `false`.
|
|
14
|
+
*/
|
|
15
|
+
export declare const AI_DRAWER_STATE_COMMAND: import("lexical").LexicalCommand<boolean>;
|
|
16
|
+
//# sourceMappingURL=commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../src/plugins/lexical/commands.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAYH,eAAO,MAAM,wBAAwB,2CAA4C,CAAA;AAEjF;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,2CAAoD,CAAA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Lexical commands for the AI drawer, split out of `plugin.tsx` so the
|
|
10
|
+
* extension definition (and any toolbar contribution) can reference them
|
|
11
|
+
* without statically importing the drawer's React component graph. This
|
|
12
|
+
* keeps `AiLexicalExtension` light enough to be referenced from an
|
|
13
|
+
* eagerly-evaluated admin/client config.
|
|
14
|
+
*/
|
|
15
|
+
import { createCommand } from 'lexical';
|
|
16
|
+
export const TOGGLE_AI_DRAWER_COMMAND = createCommand('TOGGLE_AI_DRAWER_COMMAND');
|
|
17
|
+
/**
|
|
18
|
+
* Broadcasts the AI drawer's open/closed state so contributed UI (the
|
|
19
|
+
* toolbar button) can show an active visual cue. Dispatched by the drawer
|
|
20
|
+
* plugin whenever `open` changes — including closes triggered from the
|
|
21
|
+
* drawer's own controls. Observers register a listener and return `false`.
|
|
22
|
+
*/
|
|
23
|
+
export const AI_DRAWER_STATE_COMMAND = createCommand('AI_DRAWER_STATE_COMMAND');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../../../src/plugins/lexical/extension.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../../../src/plugins/lexical/extension.tsx"],"names":[],"mappings":"AA0EA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,mHAyB7B,CAAA"}
|
|
@@ -7,12 +7,23 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
7
7
|
*
|
|
8
8
|
* Copyright (c) Infonomic Company Limited
|
|
9
9
|
*/
|
|
10
|
-
import { useEffect, useState } from 'react';
|
|
11
|
-
import { BylineToolbarExtension, useToolbarActiveEditor, } from '@byline/richtext-lexical';
|
|
10
|
+
import { lazy, Suspense, useEffect, useState } from 'react';
|
|
11
|
+
import { BylineToolbarExtension, useToolbarActiveEditor, } from '@byline/richtext-lexical/config';
|
|
12
12
|
import { AiIcon } from '@byline/ui/react';
|
|
13
13
|
import { ReactExtension } from '@lexical/react/ReactExtension';
|
|
14
14
|
import { COMMAND_PRIORITY_LOW, configExtension, declarePeerDependency, defineExtension, } from 'lexical';
|
|
15
|
-
import { AI_DRAWER_STATE_COMMAND,
|
|
15
|
+
import { AI_DRAWER_STATE_COMMAND, TOGGLE_AI_DRAWER_COMMAND } from './commands';
|
|
16
|
+
/**
|
|
17
|
+
* The AI drawer is dynamic-imported so that merely *referencing*
|
|
18
|
+
* `AiLexicalExtension` (e.g. from an eagerly-evaluated admin/client
|
|
19
|
+
* config) does not pull the drawer's React component graph — and its
|
|
20
|
+
* Anthropic/OpenAI/Google-adjacent imports — into the importing bundle.
|
|
21
|
+
* The chunk loads on first editor mount, behind the editor's own lazy
|
|
22
|
+
* boundary; the inner `Suspense` is a belt-and-braces fallback.
|
|
23
|
+
*/
|
|
24
|
+
const AiPluginLexical = lazy(async () => ({
|
|
25
|
+
default: (await import('./plugin')).AiPluginLexical,
|
|
26
|
+
}));
|
|
16
27
|
function AiToolbarButton() {
|
|
17
28
|
const editor = useToolbarActiveEditor();
|
|
18
29
|
const [isOpen, setIsOpen] = useState(false);
|
|
@@ -42,7 +53,13 @@ function AiToolbarButton() {
|
|
|
42
53
|
*/
|
|
43
54
|
export const AiLexicalExtension = defineExtension({
|
|
44
55
|
name: '@byline/ai/Lexical',
|
|
45
|
-
dependencies: [
|
|
56
|
+
dependencies: [
|
|
57
|
+
configExtension(ReactExtension, {
|
|
58
|
+
decorators: [
|
|
59
|
+
_jsx(Suspense, { fallback: null, children: _jsx(AiPluginLexical, {}) }, "d"),
|
|
60
|
+
],
|
|
61
|
+
}),
|
|
62
|
+
],
|
|
46
63
|
peerDependencies: [
|
|
47
64
|
declarePeerDependency(BylineToolbarExtension.name, {
|
|
48
65
|
items: [
|
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Copyright (c) Infonomic Company Limited
|
|
7
7
|
*/
|
|
8
|
+
export { TOGGLE_AI_DRAWER_COMMAND } from './commands';
|
|
8
9
|
export { AiLexicalExtension } from './extension';
|
|
9
|
-
export { AiPluginLexical, TOGGLE_AI_DRAWER_COMMAND } from './plugin';
|
|
10
10
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/lexical/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/lexical/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAA;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -6,13 +6,5 @@
|
|
|
6
6
|
* Copyright (c) Infonomic Company Limited
|
|
7
7
|
*/
|
|
8
8
|
import * as React from 'react';
|
|
9
|
-
export declare const TOGGLE_AI_DRAWER_COMMAND: import("lexical").LexicalCommand<unknown>;
|
|
10
|
-
/**
|
|
11
|
-
* Broadcasts the AI drawer's open/closed state so contributed UI (the
|
|
12
|
-
* toolbar button) can show an active visual cue. Dispatched by the drawer
|
|
13
|
-
* plugin whenever `open` changes — including closes triggered from the
|
|
14
|
-
* drawer's own controls. Observers register a listener and return `false`.
|
|
15
|
-
*/
|
|
16
|
-
export declare const AI_DRAWER_STATE_COMMAND: import("lexical").LexicalCommand<boolean>;
|
|
17
9
|
export declare const AiPluginLexical: React.MemoExoticComponent<() => React.JSX.Element | undefined>;
|
|
18
10
|
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/lexical/plugin.tsx"],"names":[],"mappings":"AAEA;;;;;;GAMG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/lexical/plugin.tsx"],"names":[],"mappings":"AAEA;;;;;;GAMG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AA6B9B,eAAO,MAAM,eAAe,kCAAmC,KAAK,CAAC,GAAG,CAAC,OAAO,GAAG,SAAS,CAyY1F,CAAA"}
|
|
@@ -13,19 +13,12 @@ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext
|
|
|
13
13
|
import { mergeRegister } from '@lexical/utils';
|
|
14
14
|
import {
|
|
15
15
|
// CLEAR_EDITOR_COMMAND,
|
|
16
|
-
COMMAND_PRIORITY_CRITICAL, COMMAND_PRIORITY_NORMAL,
|
|
16
|
+
COMMAND_PRIORITY_CRITICAL, COMMAND_PRIORITY_NORMAL, SELECTION_CHANGE_COMMAND, } from 'lexical';
|
|
17
17
|
import { useAiPublicConfig } from '../../config/ai-provider';
|
|
18
18
|
import { AiPluginBase } from '../ai-plugin-base';
|
|
19
|
+
import { AI_DRAWER_STATE_COMMAND, TOGGLE_AI_DRAWER_COMMAND } from './commands';
|
|
19
20
|
import { createEmptyEditorState } from './create-empty-editor-state';
|
|
20
21
|
import { importHtmlToSerializedEditorState } from './import-html';
|
|
21
|
-
export const TOGGLE_AI_DRAWER_COMMAND = createCommand('TOGGLE_AI_DRAWER_COMMAND');
|
|
22
|
-
/**
|
|
23
|
-
* Broadcasts the AI drawer's open/closed state so contributed UI (the
|
|
24
|
-
* toolbar button) can show an active visual cue. Dispatched by the drawer
|
|
25
|
-
* plugin whenever `open` changes — including closes triggered from the
|
|
26
|
-
* drawer's own controls. Observers register a listener and return `false`.
|
|
27
|
-
*/
|
|
28
|
-
export const AI_DRAWER_STATE_COMMAND = createCommand('AI_DRAWER_STATE_COMMAND');
|
|
29
22
|
const emptyInstructionState = {
|
|
30
23
|
prompt: '',
|
|
31
24
|
editor: null,
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@byline/ai",
|
|
3
3
|
"private": false,
|
|
4
4
|
"license": "MPL-2.0",
|
|
5
|
-
"version": "3.
|
|
5
|
+
"version": "3.1.1",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": ">=20.9.0"
|
|
8
8
|
},
|
|
@@ -66,9 +66,9 @@
|
|
|
66
66
|
"react-error-boundary": "^6.1.1",
|
|
67
67
|
"uuid": "^14.0.0",
|
|
68
68
|
"zod": "^4.4.3",
|
|
69
|
-
"@byline/
|
|
70
|
-
"@byline/
|
|
71
|
-
"@byline/
|
|
69
|
+
"@byline/core": "3.1.1",
|
|
70
|
+
"@byline/ui": "3.1.1",
|
|
71
|
+
"@byline/richtext-lexical": "3.1.1"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
74
|
"@biomejs/biome": "2.4.15",
|