@mostajs/chatbot 0.2.0 → 0.3.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/CHANGELOG.md +8 -0
- package/README.md +116 -15
- package/dist/agent.d.ts +39 -0
- package/dist/agent.js +14 -0
- package/dist/client.d.ts +9 -1
- package/dist/client.js +40 -5
- package/dist/index.d.ts +15 -0
- package/dist/index.js +18 -1
- package/llms.txt +4 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
**Auteur** : Dr Hamid MADANI <drmdh@msn.com>
|
|
4
4
|
|
|
5
|
+
## 0.3.0 — 2026-06-11
|
|
6
|
+
- **Agent assignable (générique)** : l'assistant devient un **acteur de 1ʳᵉ classe**. Nouveau `src/agent.ts` —
|
|
7
|
+
`AgentIdentity {id,name,kind:"assistant"}` (config `createChatbot({agent:{id?,name?}})`, défaut `assistant`/`Assistant`)
|
|
8
|
+
+ **`AssignableAgentPort`** (contrat d'**injection** : l'app hôte fournit la liaison de SON domaine — CRM→Employee/commande,
|
|
9
|
+
race-event→un autre acteur). `createChatbot` accepte `agent?`/`assignable?` et expose `agent()`, `isAgent(id)`,
|
|
10
|
+
`ensureAssignable()`, `assignableLabel(id)`. Le module reste **agnostique** (aucune notion d'« Employee »). Compat **100 %**
|
|
11
|
+
(options additives). Exports : `DEFAULT_AGENT`, `resolveAgent`, types `AgentIdentity`/`AgentConfig`/`AssignableAgentPort`.
|
|
12
|
+
|
|
5
13
|
## 0.2.0 — 2026-06-10
|
|
6
14
|
- **Extraction en modules (façon @mostajs/orm)** : la couche LLM et la boucle/routeur quittent le chatbot.
|
|
7
15
|
- **`@mostajs/llm`** : dialectes (1 par IA) + registre + types function-calling (déplacés depuis `src/dialects/`).
|
package/README.md
CHANGED
|
@@ -4,17 +4,18 @@
|
|
|
4
4
|
|
|
5
5
|
Assistant / copilote / agent conversationnel **générique et réutilisable** pour les apps `@mostajs/*`.
|
|
6
6
|
**Activable/désactivable** et **entièrement piloté par `.env`**. Backends pluggables (`scripted` sans IA,
|
|
7
|
-
`ai` avec LLM), **providers LLM pluggables avec fallback** (`anthropic`/`claude-opus-4-8`,
|
|
8
|
-
ancrage **tool-use** sur les données de l'app, **recherche web** optionnelle
|
|
7
|
+
`ai` avec LLM, `router` hybride), **providers LLM pluggables avec fallback** (`anthropic`/`claude-opus-4-8`,
|
|
8
|
+
`deepseek`), ancrage **tool-use** sur les données de l'app, **recherche web** optionnelle, et l'assistant
|
|
9
|
+
peut devenir un **membre du personnel assignable** dans votre domaine. Registres façon dialectes ORM.
|
|
9
10
|
|
|
10
|
-
> Statut : **0.0
|
|
11
|
+
> Statut : **0.3.0**. Voir `llms.txt` pour l'API dense et `CHANGELOG.md` pour l'historique.
|
|
11
12
|
|
|
12
13
|
## Configuration (`.env` — tout par config)
|
|
13
14
|
```
|
|
14
15
|
CHATBOT_ENABLED=1 # interrupteur maître (défaut 0)
|
|
15
16
|
CHATBOT_ROLES=admin,employe # vide = tous
|
|
16
17
|
CHATBOT_MODE=assistant # assistant | agent
|
|
17
|
-
CHATBOT_BACKEND=
|
|
18
|
+
CHATBOT_BACKEND=router # scripted (défaut) | ai | router (hybride : intents sans IA, IA en repli)
|
|
18
19
|
CHATBOT_PROVIDERS=deepseek,anthropic # liste priorité + fallback
|
|
19
20
|
CHATBOT_MODEL= # vide ⇒ défaut du provider
|
|
20
21
|
ANTHROPIC_API_KEY=... # provider anthropic
|
|
@@ -24,27 +25,127 @@ CHATBOT_WEB_SEARCH=0 # recherche web (anthropic)
|
|
|
24
25
|
CHATBOT_EFFORT=high
|
|
25
26
|
```
|
|
26
27
|
|
|
27
|
-
##
|
|
28
|
+
## 1. Intégrer le chatbot dans n'importe quelle application
|
|
29
|
+
|
|
30
|
+
L'app fournit son **profil métier** (`domain`), ses **outils** (`tools`) et, en option, ses **intents**
|
|
31
|
+
déterministes. Le module route vers le backend configuré (`.env`).
|
|
32
|
+
|
|
28
33
|
```ts
|
|
29
|
-
// serveur
|
|
30
|
-
import { createChatbot
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
// serveur (un seul endroit) — lib/chatbot.ts
|
|
35
|
+
import { createChatbot } from "@mostajs/chatbot";
|
|
36
|
+
|
|
37
|
+
const bot = createChatbot({
|
|
38
|
+
domain: {
|
|
39
|
+
appName: "Mon App",
|
|
40
|
+
description: "Décrit le métier → injecté dans le prompt système.",
|
|
41
|
+
locale: "fr",
|
|
42
|
+
rules: ["Toujours demander confirmation avant une action.", "Ne jamais exposer de secret."],
|
|
43
|
+
},
|
|
44
|
+
// ...tools / intents : voir §3
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Server action consommée par le widget
|
|
48
|
+
export async function askAction(text: string): Promise<string> {
|
|
49
|
+
const actor = await getActor(); // { id, role, permissions }
|
|
50
|
+
if (!bot.enabled()) return "Assistant désactivé.";
|
|
51
|
+
return bot.ask([{ role: "user", content: text }], actor);
|
|
52
|
+
}
|
|
37
53
|
```
|
|
38
54
|
```tsx
|
|
39
|
-
// client (widget)
|
|
55
|
+
// client (widget bulle + panneau)
|
|
40
56
|
import { Chatbot } from "@mostajs/chatbot/client";
|
|
41
|
-
<Chatbot send={
|
|
57
|
+
<Chatbot send={askAction} title="Assistant" greeting="Bonjour 👋" />
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
> Le widget est `"use client"`. Importez `createChatbot` (serveur) à part et passez-lui un `send()` (server action).
|
|
61
|
+
|
|
62
|
+
## 2. Faire de l'assistant un **membre du personnel** (agent assignable)
|
|
63
|
+
|
|
64
|
+
L'assistant est un **acteur de première classe** : il a une **identité** (`agent`) et, via le contrat
|
|
65
|
+
d'injection **`AssignableAgentPort`**, l'app le **branche comme acteur assignable de SON domaine** — un
|
|
66
|
+
employé qu'on assigne à une tâche, un opérateur, un agent de traitement… Le module reste **agnostique** :
|
|
67
|
+
il ne connaît ni « employé », ni « commande » ; **vous** fournissez la liaison.
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { createChatbot, type AssignableAgentPort } from "@mostajs/chatbot";
|
|
71
|
+
|
|
72
|
+
// L'adaptateur de VOTRE domaine : ici, l'agent est matérialisé comme un "employé" assignable.
|
|
73
|
+
// (Une autre app le brancherait sur une autre entité — ou pas du tout.)
|
|
74
|
+
const staffAgent: AssignableAgentPort = {
|
|
75
|
+
// seed idempotent → renvoie l'id de l'agent côté hôte (apparaît alors dans vos listes d'assignation)
|
|
76
|
+
ensure: async () => upsertEmployee({ email: "assistant@app.bot", name: "🤖 Assistant" }),
|
|
77
|
+
// cet id d'acteur est-il l'agent ?
|
|
78
|
+
isAgent: async (id) => (await getEmployee(id))?.email === "assistant@app.bot",
|
|
79
|
+
label: () => "🤖 Assistant",
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const bot = createChatbot({
|
|
83
|
+
domain: { appName: "Mon App", description: "…", locale: "fr" },
|
|
84
|
+
agent: { id: "assistant", name: "🤖 Assistant" }, // identité (défaut: { id:"assistant", name:"Assistant" })
|
|
85
|
+
assignable: staffAgent, // liaison au domaine
|
|
86
|
+
// tools/intents…
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
await bot.ensureAssignable(); // garantit que l'agent existe comme acteur assignable (au boot)
|
|
90
|
+
bot.agent(); // { id:"assistant", name:"🤖 Assistant", kind:"assistant" }
|
|
91
|
+
await bot.isAgent(someActorId); // true si cet acteur EST l'assistant
|
|
92
|
+
bot.assignableLabel(someActorId); // libellé d'affichage côté hôte
|
|
42
93
|
```
|
|
43
94
|
|
|
95
|
+
Schéma : **le module possède le *concept*** (identité + `AssignableAgentPort`), **votre app possède la
|
|
96
|
+
*liaison*** (l'adaptateur ci-dessus). Vous pouvez ainsi assigner un travail à l'assistant comme à un humain,
|
|
97
|
+
et — combiné aux outils (§3) — lui faire **traiter** ce travail.
|
|
98
|
+
|
|
99
|
+
## 3. Lui faire **exécuter des actions** (outils gardés)
|
|
100
|
+
|
|
101
|
+
Un **outil** = une fonction de votre domaine que l'assistant peut appeler. Lecture seule par défaut ;
|
|
102
|
+
les actions sensibles sont **gardées par permission** (RBAC) et, idéalement, par une **confirmation**
|
|
103
|
+
(human-in-the-loop). Le backend `ai` exécute la boucle tool-use ; le backend `router` peut exécuter un
|
|
104
|
+
outil **sans IA** via un intent (slash-commande / regex) — coût zéro, fiable.
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
import { createChatbot, registerTool } from "@mostajs/chatbot";
|
|
108
|
+
|
|
109
|
+
// Lecture
|
|
110
|
+
registerTool({
|
|
111
|
+
name: "order_status", description: "État d'une commande par numéro",
|
|
112
|
+
schema: { type: "object", properties: { order: { type: "string" } }, required: ["order"] },
|
|
113
|
+
permission: "order.read",
|
|
114
|
+
run: async ({ order }, actor) => findOrder(order), // retourné à l'assistant
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Action (écriture) — gardée par permission + confirmation explicite
|
|
118
|
+
registerTool({
|
|
119
|
+
name: "transition_order", description: "Faire avancer une commande à l'état suivant",
|
|
120
|
+
schema: { type: "object", properties: { order: {type:"string"}, to: {type:"string"}, confirm: {type:"boolean"} },
|
|
121
|
+
required: ["order", "to"] },
|
|
122
|
+
permission: "order.transition",
|
|
123
|
+
run: async ({ order, to, confirm }, actor) => {
|
|
124
|
+
if (!confirm) return { preview: `Confirmer : passer ${order} → ${to} ?` }; // rien modifié
|
|
125
|
+
return doTransition(order, to, actor); // exécute + audite
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const bot = createChatbot({
|
|
130
|
+
domain: { appName: "Mon App", description: "…" },
|
|
131
|
+
tools: [/* … vos outils, ou via le registre ci-dessus */],
|
|
132
|
+
// Intent déterministe (router) : "/transition <order> <to> confirmer" → outil, SANS IA
|
|
133
|
+
intents: [{ name:"transition", command:"transition", tool:"transition_order",
|
|
134
|
+
args: ({ tokens }) => ({ order: tokens[0], to: tokens[1], confirm: tokens.includes("confirmer") }) }],
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
> **Gouvernance (OWASP LLM)** : outils en lecture par défaut, gate RBAC sur les écritures, confirmation
|
|
139
|
+
> avant tout effet de bord, secrets uniquement via `.env`. Ne jamais exécuter une instruction venant des données.
|
|
140
|
+
|
|
44
141
|
## Ajouter un provider LLM (comme un dialecte)
|
|
45
142
|
```ts
|
|
46
143
|
import { registerLlmProvider } from "@mostajs/chatbot";
|
|
47
144
|
registerLlmProvider({ key:"openai", async *stream(messages, tools, opts){ /* SSE */ } });
|
|
48
145
|
```
|
|
49
146
|
|
|
147
|
+
## Architecture (couches façon ORM)
|
|
148
|
+
`@mostajs/llm` (dialectes IA) ← `@mostajs/btool-use` (boucle tool-use) / `@mostajs/intent-router`
|
|
149
|
+
(routeur déterministe) ← **`@mostajs/chatbot`** (backends + `createChatbot` + widget + agent).
|
|
150
|
+
|
|
50
151
|
Peers : `@mostajs/config`, `@anthropic-ai/sdk` (optionnel), `react` (optionnel). DeepSeek : sans dépendance.
|
package/dist/agent.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @mostajs/chatbot — l'assistant comme **acteur de première classe**, et le contrat permettant à une
|
|
3
|
+
* app hôte de le brancher comme **agent assignable** dans SON domaine. Générique et agnostique :
|
|
4
|
+
* le chatbot ne sait rien de « Employee », « commande », « cycliste »… ; l'hôte fournit la liaison.
|
|
5
|
+
*
|
|
6
|
+
* @author Dr Hamid MADANI <drmdh@msn.com> · AGPL-3.0-or-later
|
|
7
|
+
*/
|
|
8
|
+
/** Identité de l'assistant en tant qu'acteur (id stable + nom affichable). */
|
|
9
|
+
export interface AgentIdentity {
|
|
10
|
+
/** Id stable de l'agent côté chatbot (défaut « assistant »). */
|
|
11
|
+
id: string;
|
|
12
|
+
/** Nom affichable (défaut « Assistant »). */
|
|
13
|
+
name: string;
|
|
14
|
+
kind: "assistant";
|
|
15
|
+
}
|
|
16
|
+
/** Configuration optionnelle de l'identité de l'agent passée à `createChatbot`. */
|
|
17
|
+
export type AgentConfig = {
|
|
18
|
+
id?: string;
|
|
19
|
+
name?: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Contrat d'**injection** : comment l'app hôte matérialise l'agent comme **acteur assignable** dans
|
|
23
|
+
* son propre domaine (CRM → Employee assigné aux commandes ; race-event → un autre acteur ; etc.).
|
|
24
|
+
* Le module possède le *concept* ; l'hôte possède la *liaison*. Toutes les méthodes sont optionnelles
|
|
25
|
+
* à fournir côté hôte sauf `ensure`/`isAgent`.
|
|
26
|
+
*/
|
|
27
|
+
export interface AssignableAgentPort {
|
|
28
|
+
/** Seed idempotent de l'agent comme acteur assignable de l'hôte ; renvoie son id côté hôte. */
|
|
29
|
+
ensure(): Promise<string>;
|
|
30
|
+
/** Cet id d'acteur (côté hôte) est-il l'agent-assistant ? */
|
|
31
|
+
isAgent(id: string | undefined): boolean | Promise<boolean>;
|
|
32
|
+
/** Libellé d'affichage optionnel de l'agent côté hôte (ex. « 🤖 Assistant TRADING »). */
|
|
33
|
+
label?(id: string): string;
|
|
34
|
+
}
|
|
35
|
+
/** Identité par défaut si l'app n'en fournit aucune. */
|
|
36
|
+
export declare const DEFAULT_AGENT: AgentIdentity;
|
|
37
|
+
/** Résout l'identité de l'agent depuis la config (valeurs par défaut sûres). */
|
|
38
|
+
export declare function resolveAgent(cfg?: AgentConfig): AgentIdentity;
|
|
39
|
+
//# sourceMappingURL=agent.d.ts.map
|
package/dist/agent.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @mostajs/chatbot — l'assistant comme **acteur de première classe**, et le contrat permettant à une
|
|
3
|
+
* app hôte de le brancher comme **agent assignable** dans SON domaine. Générique et agnostique :
|
|
4
|
+
* le chatbot ne sait rien de « Employee », « commande », « cycliste »… ; l'hôte fournit la liaison.
|
|
5
|
+
*
|
|
6
|
+
* @author Dr Hamid MADANI <drmdh@msn.com> · AGPL-3.0-or-later
|
|
7
|
+
*/
|
|
8
|
+
/** Identité par défaut si l'app n'en fournit aucune. */
|
|
9
|
+
export const DEFAULT_AGENT = { id: "assistant", name: "Assistant", kind: "assistant" };
|
|
10
|
+
/** Résout l'identité de l'agent depuis la config (valeurs par défaut sûres). */
|
|
11
|
+
export function resolveAgent(cfg) {
|
|
12
|
+
return { id: cfg?.id ?? DEFAULT_AGENT.id, name: cfg?.name ?? DEFAULT_AGENT.name, kind: "assistant" };
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=agent.js.map
|
package/dist/client.d.ts
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
interface Msg {
|
|
2
|
+
role: "user" | "assistant";
|
|
3
|
+
content: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function Chatbot({ send, title, greeting, loadHistory, onExport, onReset }: {
|
|
2
6
|
send: (text: string) => Promise<string>;
|
|
3
7
|
title?: string;
|
|
4
8
|
greeting?: string;
|
|
9
|
+
loadHistory?: () => Promise<Msg[]>;
|
|
10
|
+
onExport?: (format: "html" | "pdf") => Promise<string | void>;
|
|
11
|
+
onReset?: () => Promise<void>;
|
|
5
12
|
}): import("react").JSX.Element;
|
|
13
|
+
export {};
|
|
6
14
|
//# sourceMappingURL=client.d.ts.map
|
package/dist/client.js
CHANGED
|
@@ -1,17 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @mostajs/chatbot/client — widget React
|
|
3
|
-
*
|
|
4
|
-
* (
|
|
2
|
+
* @mostajs/chatbot/client — widget React (bulle + panneau). L'app fournit `send(text)` (→ endpoint
|
|
3
|
+
* serveur → createChatbot). Optionnel : `loadHistory` (reprend le fil à la 1ʳᵉ ouverture), `onExport`
|
|
4
|
+
* (exporte la conversation, ouvre l'URL renvoyée), `onReset` (nouvelle conversation). Styles `cbot-*` côté hôte.
|
|
5
5
|
* @author Dr Hamid MADANI <drmdh@msn.com> · AGPL-3.0-or-later
|
|
6
6
|
*/
|
|
7
7
|
"use client";
|
|
8
8
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
9
9
|
import { useState } from "react";
|
|
10
|
-
export function Chatbot({ send, title = "Assistant", greeting = "Bonjour 👋" }) {
|
|
10
|
+
export function Chatbot({ send, title = "Assistant", greeting = "Bonjour 👋", loadHistory, onExport, onReset }) {
|
|
11
11
|
const [open, setOpen] = useState(false);
|
|
12
12
|
const [msgs, setMsgs] = useState([{ role: "assistant", content: greeting }]);
|
|
13
13
|
const [val, setVal] = useState("");
|
|
14
14
|
const [busy, setBusy] = useState(false);
|
|
15
|
+
const [loaded, setLoaded] = useState(false);
|
|
16
|
+
async function toggle() {
|
|
17
|
+
const willOpen = !open;
|
|
18
|
+
setOpen(willOpen);
|
|
19
|
+
if (willOpen && !loaded && loadHistory) {
|
|
20
|
+
setLoaded(true);
|
|
21
|
+
try {
|
|
22
|
+
const h = await loadHistory();
|
|
23
|
+
if (h && h.length)
|
|
24
|
+
setMsgs([{ role: "assistant", content: greeting }, ...h]);
|
|
25
|
+
}
|
|
26
|
+
catch { /* ignore */ }
|
|
27
|
+
}
|
|
28
|
+
}
|
|
15
29
|
const submit = async (e) => {
|
|
16
30
|
e.preventDefault();
|
|
17
31
|
const t = val.trim();
|
|
@@ -29,6 +43,27 @@ export function Chatbot({ send, title = "Assistant", greeting = "Bonjour 👋" }
|
|
|
29
43
|
}
|
|
30
44
|
setBusy(false);
|
|
31
45
|
};
|
|
32
|
-
|
|
46
|
+
async function doExport(fmt) {
|
|
47
|
+
if (!onExport || busy)
|
|
48
|
+
return;
|
|
49
|
+
setBusy(true);
|
|
50
|
+
try {
|
|
51
|
+
const url = await onExport(fmt);
|
|
52
|
+
if (typeof url === "string" && url)
|
|
53
|
+
window.open(url, "_blank");
|
|
54
|
+
}
|
|
55
|
+
catch { /* ignore */ }
|
|
56
|
+
setBusy(false);
|
|
57
|
+
}
|
|
58
|
+
async function doReset() {
|
|
59
|
+
if (!onReset)
|
|
60
|
+
return;
|
|
61
|
+
try {
|
|
62
|
+
await onReset();
|
|
63
|
+
}
|
|
64
|
+
catch { /* ignore */ }
|
|
65
|
+
setMsgs([{ role: "assistant", content: greeting }]);
|
|
66
|
+
}
|
|
67
|
+
return (_jsxs("div", { className: "cbot", children: [open ? (_jsxs("div", { className: "cbot-panel", role: "dialog", children: [_jsxs("div", { className: "cbot-head", children: [_jsx("span", { children: title }), _jsxs("span", { style: { display: "flex", gap: 4, alignItems: "center" }, children: [onReset ? _jsx("button", { className: "cbot-x", title: "Nouvelle conversation", onClick: doReset, children: "\uD83D\uDD04" }) : null, onExport ? _jsx("button", { className: "cbot-x", title: "Exporter (HTML)", onClick: () => doExport("html"), children: "\u2913" }) : null, onExport ? _jsx("button", { className: "cbot-x", title: "Exporter (PDF)", style: { fontSize: ".7rem" }, onClick: () => doExport("pdf"), children: "PDF" }) : null, _jsx("button", { className: "cbot-x", onClick: () => setOpen(false), "aria-label": "Fermer", children: "\u00D7" })] })] }), _jsxs("div", { className: "cbot-msgs", children: [msgs.map((m, i) => _jsx("div", { className: `cbot-msg ${m.role}`, children: m.content }, i)), busy ? _jsx("div", { className: "cbot-msg assistant cbot-typing", children: "\u2026" }) : null] }), _jsxs("form", { className: "cbot-form", onSubmit: submit, children: [_jsx("input", { value: val, onChange: (e) => setVal(e.target.value), placeholder: "Votre question\u2026" }), _jsx("button", { className: "cbot-send", type: "submit", disabled: busy, children: "\u27A4" })] })] })) : null, _jsx("button", { className: "cbot-fab", onClick: toggle, "aria-label": title, children: "\uD83E\uDD16" })] }));
|
|
33
68
|
}
|
|
34
69
|
//# sourceMappingURL=client.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -16,19 +16,34 @@ import "./backends/scripted.js";
|
|
|
16
16
|
import "./backends/ai.js";
|
|
17
17
|
import "./backends/router.js";
|
|
18
18
|
import type { ChatChunk, ChatMessage, ChatActor, DomainProfile, ChatTool, ChatIntent } from "./types.js";
|
|
19
|
+
import { type AgentConfig, type AgentIdentity, type AssignableAgentPort } from "./agent.js";
|
|
19
20
|
export interface ChatbotOptions {
|
|
20
21
|
domain: DomainProfile;
|
|
21
22
|
tools?: ChatTool[];
|
|
22
23
|
intents?: ChatIntent[];
|
|
24
|
+
/** Identité de l'assistant comme acteur (id/nom) — défaut `{ id:"assistant", name:"Assistant" }`. */
|
|
25
|
+
agent?: AgentConfig;
|
|
26
|
+
/** Liaison (DI) rendant l'agent **assignable** dans le domaine de l'app hôte (cf. `AssignableAgentPort`). */
|
|
27
|
+
assignable?: AssignableAgentPort;
|
|
23
28
|
}
|
|
24
29
|
export declare function createChatbot(options: ChatbotOptions): {
|
|
25
30
|
enabled: () => boolean;
|
|
26
31
|
stream: (messages: ChatMessage[], actor: ChatActor) => AsyncIterable<ChatChunk>;
|
|
27
32
|
ask: (messages: ChatMessage[], actor: ChatActor) => Promise<string>;
|
|
33
|
+
/** Identité de l'assistant (acteur de 1ʳᵉ classe). */
|
|
34
|
+
agent: () => AgentIdentity;
|
|
35
|
+
/** Cet id d'acteur (côté hôte) est-il l'agent ? Délègue au port d'assignation s'il est fourni. */
|
|
36
|
+
isAgent: (id?: string) => Promise<boolean>;
|
|
37
|
+
/** Garantit (seed idempotent) l'agent comme acteur assignable de l'hôte → renvoie son id côté hôte. */
|
|
38
|
+
ensureAssignable: () => Promise<string>;
|
|
39
|
+
/** Libellé d'affichage de l'agent côté hôte (si le port en fournit un). */
|
|
40
|
+
assignableLabel: (id: string) => string | undefined;
|
|
28
41
|
};
|
|
29
42
|
export type { ChatbotOptions as Options };
|
|
30
43
|
export type { AskContext, ChatChunk, ChatMessage, ChatActor, DomainProfile, ChatTool, ChatIntent, IChatBackend, ILlmProvider, ILlmDialect, ToolCall, LlmMessage, LlmTurn, ChatbotMode, LlmStreamOpts, } from "./types.js";
|
|
31
44
|
export { registerBackend, getBackend, listBackends, registerTool, getTool, listTools } from "./registry.js";
|
|
45
|
+
export { DEFAULT_AGENT, resolveAgent } from "./agent.js";
|
|
46
|
+
export type { AgentIdentity, AgentConfig, AssignableAgentPort } from "./agent.js";
|
|
32
47
|
export { registerLlmProvider, getLlmProvider, listLlmProviders, registerDialect, getDialect, listDialects, getSupportedDialects, AbstractLlmDialect, OpenAiDialect, DeepSeekDialect, MistralDialect, GroqDialect, OllamaDialect, AnthropicDialect, } from "@mostajs/llm";
|
|
33
48
|
export { runToolLoop } from "@mostajs/btool-use";
|
|
34
49
|
export { matchIntent, runIntent } from "@mostajs/intent-router";
|
package/dist/index.js
CHANGED
|
@@ -17,7 +17,10 @@ import "./backends/ai.js";
|
|
|
17
17
|
import "./backends/router.js";
|
|
18
18
|
import { getBackend } from "./registry.js";
|
|
19
19
|
import { chatbotEnabled, chatbotBackend, chatbotAllowsRole, chatbotMode } from "./config.js";
|
|
20
|
+
import { resolveAgent } from "./agent.js";
|
|
20
21
|
export function createChatbot(options) {
|
|
22
|
+
const agent = resolveAgent(options.agent);
|
|
23
|
+
const assignable = options.assignable;
|
|
21
24
|
async function* stream(messages, actor) {
|
|
22
25
|
if (!chatbotAllowsRole(actor.role)) {
|
|
23
26
|
yield { type: "error", text: "Assistant désactivé pour votre profil." };
|
|
@@ -34,9 +37,23 @@ export function createChatbot(options) {
|
|
|
34
37
|
out += c.text;
|
|
35
38
|
return out;
|
|
36
39
|
}
|
|
37
|
-
return {
|
|
40
|
+
return {
|
|
41
|
+
enabled: () => chatbotEnabled(),
|
|
42
|
+
stream,
|
|
43
|
+
ask,
|
|
44
|
+
/** Identité de l'assistant (acteur de 1ʳᵉ classe). */
|
|
45
|
+
agent: () => agent,
|
|
46
|
+
/** Cet id d'acteur (côté hôte) est-il l'agent ? Délègue au port d'assignation s'il est fourni. */
|
|
47
|
+
isAgent: async (id) => (assignable ? !!(await assignable.isAgent(id)) : id === agent.id),
|
|
48
|
+
/** Garantit (seed idempotent) l'agent comme acteur assignable de l'hôte → renvoie son id côté hôte. */
|
|
49
|
+
ensureAssignable: async () => (assignable ? assignable.ensure() : agent.id),
|
|
50
|
+
/** Libellé d'affichage de l'agent côté hôte (si le port en fournit un). */
|
|
51
|
+
assignableLabel: (id) => assignable?.label?.(id),
|
|
52
|
+
};
|
|
38
53
|
}
|
|
39
54
|
export { registerBackend, getBackend, listBackends, registerTool, getTool, listTools } from "./registry.js";
|
|
55
|
+
// Agent : l'assistant comme acteur assignable (générique ; l'app hôte fournit la liaison de domaine).
|
|
56
|
+
export { DEFAULT_AGENT, resolveAgent } from "./agent.js";
|
|
40
57
|
// Réexports de la couche LLM (compat : ces symboles vivaient dans @mostajs/chatbot avant l'extraction).
|
|
41
58
|
export { registerLlmProvider, getLlmProvider, listLlmProviders, registerDialect, getDialect, listDialects, getSupportedDialects, AbstractLlmDialect, OpenAiDialect, DeepSeekDialect, MistralDialect, GroqDialect, OllamaDialect, AnthropicDialect, } from "@mostajs/llm";
|
|
42
59
|
export { runToolLoop } from "@mostajs/btool-use";
|
package/llms.txt
CHANGED
|
@@ -10,9 +10,11 @@ défaut, RBAC) ; le module route vers le **backend** configuré et, en mode `ai`
|
|
|
10
10
|
(avec fallback). Aucune logique d'une app particulière dans le module (réutilisable partout : CRM, santé, …).
|
|
11
11
|
|
|
12
12
|
## EXPORTS
|
|
13
|
-
- `.` (serveur-safe) : `createChatbot({domain,tools})` → `{enabled(), stream
|
|
13
|
+
- `.` (serveur-safe) : `createChatbot({domain,tools,intents?,agent?,assignable?})` → `{enabled(), stream, ask,
|
|
14
|
+
agent(), isAgent(id), ensureAssignable(), assignableLabel(id)}` ;
|
|
14
15
|
`registerBackend/getBackend/listBackends`, `registerLlmProvider/getLlmProvider/listLlmProviders`,
|
|
15
|
-
`registerTool/getTool/listTools` ;
|
|
16
|
+
`registerTool/getTool/listTools` ; **agent** : `DEFAULT_AGENT`/`resolveAgent` + types `AgentIdentity`/`AgentConfig`/`AssignableAgentPort` ;
|
|
17
|
+
toute la config (`chatbot*`) ; types.
|
|
16
18
|
- `./server` : built-ins concrets (`scriptedBackend`, `aiBackend`, `anthropicProvider`, `deepseekProvider`).
|
|
17
19
|
- `./client` (React) : `<Chatbot send=… title? greeting? />` (widget bulle+panneau ; SSE en 0.3).
|
|
18
20
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mostajs/chatbot",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Assistant / copilote / agent conversationnel générique et réutilisable pour apps @mostajs/* — backends pluggables (scripted | ai), providers LLM pluggables (anthropic/claude-opus-4-8 par défaut), ancrage tool-use, recherche web optionnelle. Activable/désactivable par .env.",
|
|
5
5
|
"author": "Dr Hamid MADANI <drmdh@msn.com>",
|
|
6
6
|
"license": "AGPL-3.0-or-later",
|