@rebasepro/plugin-ai 0.12.0 → 0.12.1-canary.g009ed95

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 CHANGED
@@ -8,17 +8,52 @@ AI-powered data autofill and text autocomplete plugin for Rebase.
8
8
  pnpm add @rebasepro/plugin-ai
9
9
  ```
10
10
 
11
- **Peer dependencies:** `react >= 19.0.0`, `react-dom >= 19.0.0`, `react-router >= 6.28.0`, `react-router-dom >= 6.28.0`
11
+ **Peer dependencies:** `react >= 19.2.7`, `react-dom >= 19.2.7`, `react-router ^8`
12
12
 
13
13
  ## What This Package Does
14
14
 
15
15
  This plugin adds AI-powered capabilities to the Rebase admin panel:
16
16
 
17
- - **Form autofill** — An "Enhance" action button injected into snapshot forms that uses AI to suggest and fill field values based on collection schema and existing data.
18
- - **Editor autocomplete** — A streaming text autocomplete controller for rich text editors, powered by an AI backend.
17
+ - **Form autofill** — An "Autofill" action in the entity form footer that proposes values from the collection schema, whatever is already in the record, and an optional instruction.
18
+ - **Editor autocomplete** — A streaming inline continuation for the rich text editor.
19
19
 
20
20
  It registers as a standard `RebasePlugin`, injecting UI slots and providers automatically.
21
21
 
22
+ ### Autofill proposes; it does not edit
23
+
24
+ Clicking **Autofill** opens a review. Fields stream into that list as the model
25
+ writes them, so a long run shows progress — but the record is not touched. Each row
26
+ shows the proposed value, and the current value struck through when the proposal
27
+ would replace one. Untick anything you don't want, then **Apply** writes the rest in
28
+ a single step. **Discard** leaves the record exactly as it was.
29
+
30
+ This is a deliberate change from the FireCMS-era behaviour, where generated text was
31
+ streamed directly into the live form fields. That approach mutated the record before
32
+ anyone had agreed to it, showed half-written sentences that read as bugs, and relied
33
+ on heuristics to guess whether each token should append to or replace what you had
34
+ already typed — with no way back but retyping.
35
+
36
+ ## How it reaches a model
37
+
38
+ The plugin talks to a small hosted service that Rebase runs and pays for (Gemini 3.6 Flash, behind Rebase’s own credits). There is
39
+ **nothing to configure and no API key to obtain** — install the plugin, mount it, done.
40
+
41
+ Two consequences worth knowing:
42
+
43
+ - **Requests are anonymous.** No auth token of any kind leaves your app. The service
44
+ cannot verify a self-hosted backend's JWT (you sign it with your own secret), so
45
+ asking for one would only hand a live credential to a third party that has no use
46
+ for it. Cost is bounded by rate limits and a daily ceiling instead.
47
+ - **Your collection schema and the record's current values are sent** with each
48
+ autofill request, because the service has no other way to know the shape of what
49
+ it is filling. If that is not acceptable for your data, set `endpoint` and run the
50
+ service yourself — the reference implementation is `saas/backend/functions/ai.ts`
51
+ in the Rebase repository, and the wire format is documented in `src/api.ts`.
52
+
53
+ The plugin renders nothing until the service's `GET /status` reports itself
54
+ available, so an unreachable host or an exhausted daily quota means no Autofill
55
+ button — never a button that fails when clicked.
56
+
22
57
  ## Key Exports
23
58
 
24
59
  | Export | Type | Description |
@@ -31,38 +66,39 @@ It registers as a standard `RebasePlugin`, injecting UI slots and providers auto
31
66
 
32
67
  | Prop | Type | Default | Description |
33
68
  |---|---|---|---|
34
- | `apiKey` | `string` | Built-in default key | API key for the data enhancement service |
35
- | `getConfigForPath` | `(props: { path, collection, user }) => boolean` | | Return `false` to disable enhancement for specific paths |
36
- | `host` | `string` | — | Custom API host (development only) |
69
+ | `getConfigForPath` | `(props: { path, collection, user }) => boolean` | | Return `false` to disable autofill for specific paths |
70
+ | `endpoint` | `string` | Rebase's hosted service | Base URL of the AI service. Point it at your own deployment to keep generation inside your infrastructure |
37
71
 
38
72
  ## Quick Start
39
73
 
40
74
  ```tsx
41
75
  import { useDataEnhancementPlugin } from "@rebasepro/plugin-ai";
42
76
 
43
- // In your app setup:
44
77
  const dataEnhancementPlugin = useDataEnhancementPlugin({
45
- getConfigForPath: ({ path, collection }) => {
46
- // Disable for certain collections
47
- return collection.name !== "system_logs";
48
- }
78
+ getConfigForPath: ({ collection }) => collection.name !== "system_logs"
49
79
  });
50
80
 
51
81
  // Pass to your Rebase app:
52
- <RebaseFirebaseApp
53
- plugins={[dataEnhancementPlugin]}
54
- // ...other props
55
- />
82
+ // <Rebase plugins={[dataEnhancementPlugin]} ... />
56
83
  ```
57
84
 
85
+ ### Self-hosting the service
86
+
87
+ ```tsx
88
+ const dataEnhancementPlugin = useDataEnhancementPlugin({
89
+ endpoint: "https://ai.internal.example.com"
90
+ });
91
+ ```
92
+
93
+ Your endpoint needs to answer `GET /status`, `POST /autofill` (SSE), `POST /autocomplete`
94
+ (SSE) and `POST /prompts`.
95
+
58
96
  ### Editor AI Autocomplete
59
97
 
60
98
  ```tsx
61
99
  import { useEditorAIController } from "@rebasepro/plugin-ai";
62
100
 
63
- const aiController = useEditorAIController({
64
- getAuthToken: () => firebaseUser.getIdToken()
65
- });
101
+ const aiController = useEditorAIController();
66
102
 
67
103
  // Use in a rich text editor:
68
104
  await aiController.autocomplete(
@@ -74,6 +110,14 @@ await aiController.autocomplete(
74
110
  );
75
111
  ```
76
112
 
113
+ ## Migrating from the FireCMS-era plugin
114
+
115
+ The `apiKey` and `host` props are gone. `apiKey` shipped a hardcoded key in the
116
+ published package and pointed at a service that no longer exists; `host` is now
117
+ `endpoint` and is a supported production option rather than a development-only
118
+ escape hatch. `useEditorAIController` no longer takes `getAuthToken` — it needs no
119
+ token.
120
+
77
121
  ## Related Packages
78
122
 
79
123
  - `@rebasepro/admin` — The admin panel this plugin extends
package/dist/api.d.ts CHANGED
@@ -1,34 +1,60 @@
1
- import { EnhancedDataResult, InputProperty, SamplePromptsResult } from "./types/data_enhancement_controller";
2
- import { EntityValues } from "@rebasepro/types";
3
- export declare function enhanceDataAPIStream<M extends Record<string, unknown>>(props: {
4
- apiKey: string;
5
- entityId?: string | number;
6
- entityName: string;
7
- entityDescription?: string;
8
- propertyKey?: string;
9
- propertyInstructions?: string;
10
- values: EntityValues<M>;
11
- path: string;
12
- properties: Record<string, InputProperty>;
13
- instructions?: string;
14
- firebaseToken: string;
15
- onUpdate: (suggestions: Record<string, string | number>) => void;
16
- onUpdateDelta: (propertyKey: string, partialValue: string) => void;
17
- onError: (error: Error) => void;
18
- onEnd: (result: EnhancedDataResult) => void;
19
- host?: string;
20
- }): Promise<void>;
21
- export declare function fetchEntityPromptSuggestion<M extends object>(props: {
22
- input?: string;
23
- entityName: string;
24
- firebaseToken: string;
25
- apiKey: string;
26
- host?: string;
27
- }): Promise<SamplePromptsResult>;
1
+ import { AutofillRequest, AutofillResult, AiStatus, SamplePromptsResult } from "./types/data_enhancement_controller";
2
+ /**
3
+ * The hosted service Rebase runs for this plugin.
4
+ *
5
+ * The previous value here was `https://api.rebase.pro`, a FireCMS-era host that
6
+ * resolves but serves nothing — every path 404s — so Autofill had never worked
7
+ * in a Rebase install. This one is served by the control plane
8
+ * (`saas/backend/functions/ai.ts`). Point `endpoint` somewhere else to run your
9
+ * own; the wire format below is the whole contract.
10
+ */
11
+ export declare const DEFAULT_AI_ENDPOINT = "https://app.rebase.pro/api/functions/ai";
12
+ /**
13
+ * Ask the service whether it can serve a request at all.
14
+ *
15
+ * The plugin gates every affordance on this. A missing provider key, an
16
+ * exhausted daily quota or an unreachable host all resolve to `available:
17
+ * false`, and the Autofill button is simply not rendered — rather than
18
+ * rendered, clicked, and failed.
19
+ */
20
+ export declare function fetchAiStatus(props: {
21
+ endpoint?: string;
22
+ signal?: AbortSignal;
23
+ }): Promise<AiStatus>;
24
+ /**
25
+ * Fill a record, streaming each field as the service writes it.
26
+ *
27
+ * `onDelta` fires with more text for a field still being written; `onValue`
28
+ * fires once a field is complete and carries its final, correctly typed value.
29
+ * A caller that implements only `onValue` still ends up with the right record —
30
+ * the deltas exist so a long text field fills in visibly instead of appearing
31
+ * all at once.
32
+ */
33
+ export declare function autofillStream(props: {
34
+ request: AutofillRequest;
35
+ endpoint?: string;
36
+ signal?: AbortSignal;
37
+ onDelta: (key: string, text: string) => void;
38
+ onValue: (key: string, value: unknown) => void;
39
+ }): Promise<AutofillResult>;
40
+ /** Inline continuation for the rich-text editor. Streams plain text. */
28
41
  export declare function autocompleteStream(props: {
29
- firebaseToken: string;
30
42
  textBefore?: string;
31
- textAfter: string;
32
- host?: string;
33
- onUpdate: (delta: string) => void;
43
+ textAfter?: string;
44
+ endpoint?: string;
45
+ signal?: AbortSignal;
46
+ onDelta: (text: string) => void;
34
47
  }): Promise<string>;
48
+ /**
49
+ * Sample prompts for the Autofill menu.
50
+ *
51
+ * Failure is deliberately not thrown: the menu has built-in prompts to fall
52
+ * back on, and an empty suggestion list is a far better outcome than an error
53
+ * toast for something nobody asked for.
54
+ */
55
+ export declare function fetchPromptSuggestions(props: {
56
+ entityName: string;
57
+ input?: string;
58
+ endpoint?: string;
59
+ signal?: AbortSignal;
60
+ }): Promise<SamplePromptsResult>;
@@ -0,0 +1,16 @@
1
+ import React from "react";
2
+ /**
3
+ * The review step.
4
+ *
5
+ * Autofill used to write generated text into the live form as it streamed —
6
+ * fields mutating under the cursor, half-written sentences that looked like
7
+ * bugs, and a pile of heuristics deciding whether each token should append to
8
+ * or replace what the operator had already typed. Getting the old value back
9
+ * meant retyping it.
10
+ *
11
+ * So the generated values land here instead. Streaming still happens, and is
12
+ * still worth having — rows appear and fill in as the model works, so a long
13
+ * run shows progress — but it happens in a surface that owns nothing. The
14
+ * record changes on **Apply**, once, for the rows still ticked.
15
+ */
16
+ export declare function AutofillReviewDialog(): React.JSX.Element | null;
@@ -3,13 +3,12 @@ import { DataEnhancementController } from "../types/data_enhancement_controller"
3
3
  import { CollectionConfig } from "@rebasepro/types";
4
4
  import { PluginFormActionProps } from "@rebasepro/admin-types";
5
5
  type DataEnhancementControllerProviderProps = {
6
- apiKey: string;
7
6
  getConfigForPath?: (props: {
8
7
  path: string;
9
8
  collection: CollectionConfig;
10
9
  }) => boolean;
11
- host?: string;
10
+ endpoint?: string;
12
11
  };
13
12
  export declare const useDataEnhancementController: () => DataEnhancementController;
14
- export declare function DataEnhancementControllerProvider({ apiKey, getConfigForPath, children, host, path, collection, formContext }: PropsWithChildren<DataEnhancementControllerProviderProps & PluginFormActionProps>): React.JSX.Element;
13
+ export declare function DataEnhancementControllerProvider({ getConfigForPath, children, endpoint, path, collection, formContext }: PropsWithChildren<DataEnhancementControllerProviderProps & PluginFormActionProps>): React.JSX.Element;
15
14
  export {};
@@ -1,3 +1,3 @@
1
1
  import React from "react";
2
2
  import { PluginFormActionProps } from "@rebasepro/admin-types";
3
- export declare function FormEnhanceAction({ entityId, path, status, collection, formContext, openEntityMode }: PluginFormActionProps): React.JSX.Element | null;
3
+ export declare function FormEnhanceAction({ path, status, collection, formContext }: PluginFormActionProps): React.JSX.Element | null;
@@ -1,4 +1,13 @@
1
1
  import { EditorAIController } from "@rebasepro/admin";
2
- export declare function useEditorAIController({ getAuthToken }: {
3
- getAuthToken?: () => Promise<string>;
2
+ /**
3
+ * Inline continuation for the rich-text editor's slash command.
4
+ *
5
+ * No token is threaded through any more. The previous version demanded a
6
+ * Firebase ID token and threw `"Firebase token is required"` when it could not
7
+ * get one — in a Rebase app there is no such thing, and the token it actually
8
+ * sent was a Rebase JWT the receiving service had no way to verify. The hosted
9
+ * service authenticates nobody; see `src/api.ts`.
10
+ */
11
+ export declare function useEditorAIController({ endpoint }?: {
12
+ endpoint?: string;
4
13
  }): EditorAIController;