@moderta/mint-ai-assistant 0.1.4 → 0.1.6
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 +97 -82
- package/dist/index.d.ts +80 -24
- package/dist/mint-ai-assistant.cjs +27 -27
- package/dist/mint-ai-assistant.js +3215 -4543
- package/package.json +61 -61
package/README.md
CHANGED
|
@@ -1,85 +1,100 @@
|
|
|
1
|
-
# @moderta/mint-ai-assistant
|
|
2
|
-
|
|
3
|
-
Embeddable **Mint AI** assistant — a floating chat widget shared across Moderta apps.
|
|
4
|
-
React component, Tailwind-styled, distributed as an npm package.
|
|
5
|
-
|
|
6
|
-
## Why this exists
|
|
7
|
-
|
|
8
|
-
The same architecture as the main `frontend` (RTK Query `api-details` → `base-slice`
|
|
9
|
-
registry, scoped store), but packaged as a **library** you can drop into any React app
|
|
10
|
-
without it touching the host's styles.
|
|
11
|
-
|
|
12
|
-
- **Isolation:** Tailwind preflight is disabled and every utility is `mint-` prefixed, so
|
|
13
|
-
embedding never resets or restyles the host app. The compiled CSS is auto-injected.
|
|
14
|
-
- **Config via props**, not env vars (the package runs inside someone else's bundle).
|
|
15
|
-
- **React + ReactDOM are peer dependencies** — the host provides them.
|
|
16
|
-
|
|
17
|
-
## Install
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
npm install @moderta/mint-ai-assistant
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## Usage
|
|
24
|
-
|
|
25
|
-
```tsx
|
|
26
|
-
import { MintAIAssistant } from '@moderta/mint-ai-assistant';
|
|
27
|
-
|
|
28
|
-
export function App() {
|
|
29
|
-
return (
|
|
30
|
-
<MintAIAssistant
|
|
31
|
-
baseUrl="https://
|
|
32
|
-
getToken={() =>
|
|
1
|
+
# @moderta/mint-ai-assistant
|
|
2
|
+
|
|
3
|
+
Embeddable **Mint AI** assistant — a floating chat widget shared across Moderta apps.
|
|
4
|
+
React component, Tailwind-styled, distributed as an npm package.
|
|
5
|
+
|
|
6
|
+
## Why this exists
|
|
7
|
+
|
|
8
|
+
The same architecture as the main `frontend` (RTK Query `api-details` → `base-slice`
|
|
9
|
+
registry, scoped store), but packaged as a **library** you can drop into any React app
|
|
10
|
+
without it touching the host's styles.
|
|
11
|
+
|
|
12
|
+
- **Isolation:** Tailwind preflight is disabled and every utility is `mint-` prefixed, so
|
|
13
|
+
embedding never resets or restyles the host app. The compiled CSS is auto-injected.
|
|
14
|
+
- **Config via props**, not env vars (the package runs inside someone else's bundle).
|
|
15
|
+
- **React + ReactDOM are peer dependencies** — the host provides them.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @moderta/mint-ai-assistant
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import { MintAIAssistant } from '@moderta/mint-ai-assistant';
|
|
27
|
+
|
|
28
|
+
export function App() {
|
|
29
|
+
return (
|
|
30
|
+
<MintAIAssistant
|
|
31
|
+
baseUrl="https://context-engine.moderta.io"
|
|
32
|
+
getToken={() => sessionStorage.getItem('jwt_access_token') ?? undefined}
|
|
33
|
+
tenantId={user.companyId}
|
|
33
34
|
title="Mint AI"
|
|
34
35
|
placement="bottom-right"
|
|
35
36
|
enableExpandMode={false}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
|
45
|
-
|
|
|
46
|
-
| `
|
|
47
|
-
| `
|
|
48
|
-
| `
|
|
49
|
-
| `
|
|
50
|
-
| `
|
|
51
|
-
| `
|
|
52
|
-
| `
|
|
53
|
-
|
|
54
|
-
## API contract
|
|
55
|
-
|
|
56
|
-
The widget talks to
|
|
57
|
-
|
|
58
|
-
- `POST {baseUrl}/
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
npm
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Props (`MintAIConfig`)
|
|
43
|
+
|
|
44
|
+
| Prop | Type | Default | Notes |
|
|
45
|
+
| ---------------- | ----------------------------- | ---------------- | --------------------------------------- |
|
|
46
|
+
| `baseUrl` | `string` | — | Required. Base URL of the assistant API |
|
|
47
|
+
| `getToken` | `() => string \| Promise<…>` | — | Supabase bearer token for requests |
|
|
48
|
+
| `tenantId` | `string` | — | Sent as `tenant_id`; the caller's company id |
|
|
49
|
+
| `user` | `{ name?: string; email?: string }` | — | Signed-in identity shown in the expanded-mode sidebar |
|
|
50
|
+
| `placement` | `bottom-right \| …` | `bottom-right` | Launcher corner |
|
|
51
|
+
| `title` | `string` | `Mint AI` | Panel header title |
|
|
52
|
+
| `welcomeMessage` | `string` | greeting | Shown when there's no history |
|
|
53
|
+
| `defaultOpen` | `boolean` | `false` | Open the panel on mount |
|
|
54
|
+
|
|
55
|
+
## API contract
|
|
56
|
+
|
|
57
|
+
The widget talks to the Mint AI Context Engine (`src/api/api-details`):
|
|
58
|
+
|
|
59
|
+
- `POST {baseUrl}/query` — body `{ tenant_id, question }`, header
|
|
60
|
+
`Authorization: Bearer <token>` → `{ answer, sources: [{ chunk_id, text }], source_type }`
|
|
61
|
+
|
|
62
|
+
There is no conversation-history or feedback endpoint; conversation
|
|
63
|
+
continuity is client-side only.
|
|
64
|
+
|
|
65
|
+
## Develop
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npm install
|
|
69
|
+
npm run dev # playground host app at / (see dev/main.tsx)
|
|
70
|
+
npm run build # emits dist/ (ESM + CJS + types)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Project structure
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
src/
|
|
77
|
+
index.ts public API
|
|
78
|
+
mint-ai-assistant.tsx root component (provider + widget)
|
|
79
|
+
config/ props-based config (replaces global-config)
|
|
80
|
+
providers/ scoped provider stack
|
|
81
|
+
store/ widget-scoped Redux + chat UI slice
|
|
82
|
+
api/ RTK Query: api-details registry → base-slice
|
|
83
|
+
sections/assistant/ the chat UI (launcher, panel, list, composer)
|
|
84
|
+
components/iconify/ shared UI primitives
|
|
85
|
+
hooks/ useChat
|
|
86
|
+
types/ shared types
|
|
87
|
+
utils/ cn(), uid()
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## AI-assisted development
|
|
91
|
+
|
|
92
|
+
Repository-specific AI guidance lives in [AGENTS.md](AGENTS.md). Detailed architecture, security, testing, database, specifications, prompts and project knowledge are under [`.ai/`](.ai/); reusable Claude skills and permissions are under [`.claude/`](.claude/). Treat executable code and tests as authoritative when documentation becomes stale.
|
|
93
|
+
|
|
94
|
+
## Current architecture snapshot
|
|
95
|
+
|
|
96
|
+
Embeddable `@moderta/mint-ai-assistant` React widget/library. `src/index.ts` defines the package public API. `MintAIAssistant` wraps the UI in `AssistantProvider`; `dev/main.tsx` is a local integration harness, not a production entry point.
|
|
97
|
+
|
|
98
|
+
A host passes API base URL, optional token getter/context/placement. The provider creates configuration and Redux context; `useChat` adds an optimistic user message, calls the chat endpoint, stores the returned conversation/assistant message, and emits a system error on failure.
|
|
99
|
+
|
|
100
|
+
For implementation rules and the complete source-derived map, read [AGENTS.md](AGENTS.md) and [the architecture instructions](.ai/instructions/architecture.md).
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { BaseQueryApi } from '@reduxjs/toolkit/query';
|
|
2
|
+
import { ChatMessage } from '@moderta/api-contracts/chat';
|
|
3
|
+
import { ChatMessageStatus } from '@moderta/api-contracts/chat';
|
|
4
|
+
import { ChatRole } from '@moderta/api-contracts/chat';
|
|
5
|
+
import { FetchArgs } from '@reduxjs/toolkit/query';
|
|
6
|
+
import { FetchBaseQueryError } from '@reduxjs/toolkit/query';
|
|
7
|
+
import { FetchBaseQueryMeta } from '@reduxjs/toolkit/query';
|
|
8
|
+
import { InfiniteQueryActionCreatorResult } from '@reduxjs/toolkit/query';
|
|
9
|
+
import { InfiniteQueryDefinition } from '@reduxjs/toolkit/query';
|
|
4
10
|
import { JSX as JSX_2 } from 'react';
|
|
11
|
+
import { QueryReturnValue } from '@reduxjs/toolkit/query';
|
|
5
12
|
import { ReactNode } from 'react';
|
|
13
|
+
import { SessionSummary } from '@moderta/api-contracts/chat';
|
|
14
|
+
import { SubscriptionOptions } from '@reduxjs/toolkit/query';
|
|
6
15
|
|
|
7
16
|
export declare type AssistantFormRenderer = () => ReactNode;
|
|
8
17
|
|
|
9
|
-
export declare type AssistantPlacement =
|
|
18
|
+
export declare type AssistantPlacement = "bottom-right" | "bottom-left" | "top-right" | "top-left";
|
|
10
19
|
|
|
11
20
|
export { ChatMessage }
|
|
12
21
|
|
|
@@ -24,8 +33,21 @@ export declare interface MintAIAssistantProps extends MintAIConfig {
|
|
|
24
33
|
export declare interface MintAIConfig {
|
|
25
34
|
/** Base URL of the assistant API, e.g. `https://api.moderta.io`. */
|
|
26
35
|
baseUrl: string;
|
|
36
|
+
/** Optional stable user identifier forwarded to the chat backend. */
|
|
37
|
+
userId?: string;
|
|
27
38
|
/** Returns the bearer token for the current user (sync or async). */
|
|
28
39
|
getToken?: TokenGetter;
|
|
40
|
+
/**
|
|
41
|
+
* Tenant identifier sent as `tenant_id` with every `/query` request.
|
|
42
|
+
* In ESM this is the caller's company id. The Context Engine still
|
|
43
|
+
* re-derives it from the bearer token and rejects a mismatch.
|
|
44
|
+
*/
|
|
45
|
+
tenantId?: string;
|
|
46
|
+
/** Signed-in user's display identity, shown in the assistant UI. */
|
|
47
|
+
user?: {
|
|
48
|
+
name?: string;
|
|
49
|
+
email?: string;
|
|
50
|
+
};
|
|
29
51
|
/** Where the floating launcher sits. Default: `bottom-right`. */
|
|
30
52
|
placement?: AssistantPlacement;
|
|
31
53
|
/** Greeting shown when the chat opens with no history. */
|
|
@@ -46,34 +68,68 @@ export declare interface MintAIConfig {
|
|
|
46
68
|
|
|
47
69
|
declare type ResolvedConfig = MintAIConfig & Required<Pick<MintAIConfig, 'placement' | 'title' | 'welcomeMessage' | 'defaultOpen' | 'enableExpandMode'>>;
|
|
48
70
|
|
|
49
|
-
export
|
|
50
|
-
onClose?: () => void;
|
|
51
|
-
}): JSX_2.Element;
|
|
52
|
-
|
|
53
|
-
export declare function SampleEmptyPanel({ onClose }: {
|
|
54
|
-
onClose?: () => void;
|
|
55
|
-
}): JSX_2.Element;
|
|
56
|
-
|
|
57
|
-
export declare function SampleExpandedMode({ onCollapse, onClose, }: Readonly<{
|
|
58
|
-
onCollapse?: () => void;
|
|
59
|
-
onClose?: () => void;
|
|
60
|
-
}>): JSX_2.Element;
|
|
61
|
-
|
|
62
|
-
export declare function SampleShowcase({ initial }: {
|
|
63
|
-
initial?: Screen_2;
|
|
64
|
-
}): JSX_2.Element;
|
|
65
|
-
|
|
66
|
-
declare type Screen_2 = 'empty' | 'conversation' | 'expanded';
|
|
71
|
+
export { SessionSummary }
|
|
67
72
|
|
|
68
73
|
export declare type TokenGetter = () => string | undefined | Promise<string | undefined>;
|
|
69
74
|
|
|
70
75
|
export declare function useChat(): {
|
|
71
76
|
messages: ChatMessage[];
|
|
72
|
-
|
|
73
|
-
isLoading:
|
|
77
|
+
notice: string | null;
|
|
78
|
+
isLoading: boolean;
|
|
74
79
|
send: (raw?: string) => Promise<void>;
|
|
80
|
+
loadOlder: () => void;
|
|
81
|
+
hasOlder: boolean;
|
|
82
|
+
isLoadingOlder: boolean;
|
|
75
83
|
};
|
|
76
84
|
|
|
77
85
|
export declare function useConfig(): ResolvedConfig;
|
|
78
86
|
|
|
87
|
+
/**
|
|
88
|
+
* The Past Chats list for the expanded sidebar. Backed by the getSessions
|
|
89
|
+
* infinite query — one flat list, keyset-paginated, filtered by `search`
|
|
90
|
+
* (debounced). Re-sorts when sendMessage invalidates SessionList.
|
|
91
|
+
*/
|
|
92
|
+
export declare function useSessions(search: string): {
|
|
93
|
+
sessions: {
|
|
94
|
+
sessionId: string;
|
|
95
|
+
title: string | null;
|
|
96
|
+
status: "active" | "expired";
|
|
97
|
+
createdAt: string;
|
|
98
|
+
lastActivityAt: string;
|
|
99
|
+
expiresAt: string;
|
|
100
|
+
}[];
|
|
101
|
+
activeSessionId: string | null;
|
|
102
|
+
isLoading: boolean;
|
|
103
|
+
/** A fetch is in flight that isn't "load next page" — initial load or a new search. */
|
|
104
|
+
isReloading: boolean;
|
|
105
|
+
isError: boolean;
|
|
106
|
+
hasNextPage: boolean;
|
|
107
|
+
isFetchingNextPage: boolean;
|
|
108
|
+
loadMore: () => void;
|
|
109
|
+
openSession: (sessionId: string) => {
|
|
110
|
+
payload: string | null;
|
|
111
|
+
type: "chatUi/setActiveSessionId";
|
|
112
|
+
};
|
|
113
|
+
newChat: () => {
|
|
114
|
+
payload: undefined;
|
|
115
|
+
type: "chatUi/startNewChat";
|
|
116
|
+
};
|
|
117
|
+
refetch: (options?: Pick<SubscriptionOptions & {
|
|
118
|
+
skip?: boolean;
|
|
119
|
+
refetchOnMountOrArgChange?: boolean | number;
|
|
120
|
+
initialPageParam?: string | undefined;
|
|
121
|
+
refetchCachedPages?: boolean;
|
|
122
|
+
}, "refetchCachedPages"> | undefined) => InfiniteQueryActionCreatorResult<InfiniteQueryDefinition<string, string | undefined, (args: string | FetchArgs, api: BaseQueryApi, extraOptions: {}) => Promise<QueryReturnValue<unknown, FetchBaseQueryError, FetchBaseQueryMeta>>, "SessionList", {
|
|
123
|
+
items: {
|
|
124
|
+
sessionId: string;
|
|
125
|
+
title: string | null;
|
|
126
|
+
status: "active" | "expired";
|
|
127
|
+
createdAt: string;
|
|
128
|
+
lastActivityAt: string;
|
|
129
|
+
expiresAt: string;
|
|
130
|
+
}[];
|
|
131
|
+
nextCursor: string | null;
|
|
132
|
+
}, "chatApi", unknown>>;
|
|
133
|
+
};
|
|
134
|
+
|
|
79
135
|
export { }
|