@kieksme/csp-plugin-chat 0.8.0 → 0.9.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/README.md +2 -0
- package/dist/browser.d.ts +3 -1
- package/dist/browser.js +141 -4
- package/dist/{chunk-NHJR47VI.js → chunk-R6G6BYF4.js} +1 -1
- package/dist/server.js +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -23,3 +23,5 @@ Der System-Prompt begrenzt den Chat auf Support und Portalbedienung. Fachfremde
|
|
|
23
23
|
Optional persisted conversations and real human support are available through the Teams plugin. The UI uses `chatSupport` from the public profile and identifies real support separately from the digital assistant. See [Teams support](../../docs/teams-support.md).
|
|
24
24
|
|
|
25
25
|
For portals with an existing same-origin authenticated gateway, set `chatSupport.auth` to `session` to reuse the login without browser tokens. The API still requires a validated delegated access token supplied by the internal gateway. See [Teams support](../../docs/teams-support.md#vorhandene-portal-anmeldung-verwenden).
|
|
26
|
+
|
|
27
|
+
WebMCP tool: `chat_ask` streams one answer from `POST /api/v1/chat` and returns text, responder and sources. It changes no data but uses the chat rate limit and provider quota, so it is not marked read-only. See [WebMCP](../../docs/webmcp.md).
|
package/dist/browser.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as _kieksme_csp_sdk from '@kieksme/csp-sdk';
|
|
2
2
|
import { BrowserContext } from '@kieksme/csp-sdk';
|
|
3
|
+
import * as react from 'react';
|
|
3
4
|
|
|
4
5
|
declare function Chat(ctx: BrowserContext): react.JSX.Element;
|
|
5
6
|
declare const _default: {
|
|
6
7
|
id: string;
|
|
7
8
|
sdkVersion: string;
|
|
9
|
+
tools: _kieksme_csp_sdk.WebMcpTool[];
|
|
8
10
|
sections: {
|
|
9
11
|
id: string;
|
|
10
12
|
placement: "hero";
|
package/dist/browser.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
cspPlugin
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-R6G6BYF4.js";
|
|
4
4
|
|
|
5
|
-
// src/
|
|
6
|
-
import {
|
|
5
|
+
// src/tools.ts
|
|
6
|
+
import {
|
|
7
|
+
UNTRUSTED_NOTE,
|
|
8
|
+
webMcpError,
|
|
9
|
+
webMcpJson
|
|
10
|
+
} from "@kieksme/csp-sdk";
|
|
7
11
|
|
|
8
12
|
// src/answer.ts
|
|
9
13
|
import { safeUrl } from "@kieksme/csp-sdk";
|
|
@@ -33,6 +37,138 @@ function answerParts(text, sources, streaming = false) {
|
|
|
33
37
|
});
|
|
34
38
|
}
|
|
35
39
|
|
|
40
|
+
// src/tools.ts
|
|
41
|
+
function parseMessages(value) {
|
|
42
|
+
if (!Array.isArray(value) || value.length < 1 || value.length > 20)
|
|
43
|
+
return "messages muss 1 bis 20 Eintr\xE4ge enthalten.";
|
|
44
|
+
let total = 0;
|
|
45
|
+
const messages = [];
|
|
46
|
+
for (const item of value) {
|
|
47
|
+
const { role, content } = item ?? {};
|
|
48
|
+
if (role !== "user" && role !== "assistant" || typeof content !== "string" || content.length < 1 || content.length > 4e3)
|
|
49
|
+
return "Jede Nachricht braucht role (user|assistant) und content (1 bis 4000 Zeichen).";
|
|
50
|
+
total += content.length;
|
|
51
|
+
messages.push({ role, content });
|
|
52
|
+
}
|
|
53
|
+
if (messages.at(-1).role !== "user")
|
|
54
|
+
return "Die letzte Nachricht muss von user stammen.";
|
|
55
|
+
if (total > 16e3)
|
|
56
|
+
return "Der Verlauf darf h\xF6chstens 16000 Zeichen enthalten.";
|
|
57
|
+
return messages;
|
|
58
|
+
}
|
|
59
|
+
async function askChat(ctx, messages, signal) {
|
|
60
|
+
const response = await (ctx.request ?? fetch)(
|
|
61
|
+
ctx.config.apiUrl + "/api/v1/chat",
|
|
62
|
+
{
|
|
63
|
+
method: "POST",
|
|
64
|
+
headers: { "Content-Type": "application/json" },
|
|
65
|
+
body: JSON.stringify({ messages }),
|
|
66
|
+
signal
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
if (!response.ok || !response.body)
|
|
70
|
+
throw new Error(
|
|
71
|
+
response.status === 429 ? "Zu viele Anfragen. Bitte eine Minute warten." : "Chat derzeit nicht erreichbar."
|
|
72
|
+
);
|
|
73
|
+
const reader = response.body.getReader();
|
|
74
|
+
const decoder = new TextDecoder();
|
|
75
|
+
let buffer = "";
|
|
76
|
+
let answer = "";
|
|
77
|
+
let complete = false;
|
|
78
|
+
let responder;
|
|
79
|
+
let sources = [];
|
|
80
|
+
try {
|
|
81
|
+
while (true) {
|
|
82
|
+
const { done, value } = await reader.read();
|
|
83
|
+
buffer += decoder.decode(value, { stream: !done });
|
|
84
|
+
let boundary;
|
|
85
|
+
while ((boundary = buffer.indexOf("\n\n")) >= 0) {
|
|
86
|
+
const block = buffer.slice(0, boundary);
|
|
87
|
+
buffer = buffer.slice(boundary + 2);
|
|
88
|
+
const type = block.match(/^event: (.+)$/m)?.[1];
|
|
89
|
+
const payload = block.match(/^data: (.+)$/m)?.[1];
|
|
90
|
+
if (!payload) continue;
|
|
91
|
+
const event = JSON.parse(payload);
|
|
92
|
+
if (type === "delta") answer += event.text;
|
|
93
|
+
if (type === "responder") responder = event;
|
|
94
|
+
if (type === "sources") sources = event;
|
|
95
|
+
if (type === "error") throw new Error(event.message);
|
|
96
|
+
if (type === "done") complete = true;
|
|
97
|
+
}
|
|
98
|
+
if (done) break;
|
|
99
|
+
}
|
|
100
|
+
} finally {
|
|
101
|
+
await reader.cancel().catch(() => void 0);
|
|
102
|
+
reader.releaseLock();
|
|
103
|
+
}
|
|
104
|
+
if (!complete)
|
|
105
|
+
throw new Error(
|
|
106
|
+
"Die Verbindung wurde unterbrochen. Antwort unvollst\xE4ndig."
|
|
107
|
+
);
|
|
108
|
+
return { answer, responder, sources };
|
|
109
|
+
}
|
|
110
|
+
var chatTools = [
|
|
111
|
+
{
|
|
112
|
+
name: "chat_ask",
|
|
113
|
+
description: "Fragt den digitalen Assistenten des Portals (kennt Hilfe-Inhalte, Team, Schichten und Status). Verbraucht Chat-Kontingent (Rate-Limit pro IP) und ruft einen KI-Anbieter auf; nur nutzen, wenn die anderen Tools nicht reichen. \xC4ndert keine Daten. Die letzte Nachricht muss von user stammen.",
|
|
114
|
+
inputSchema: {
|
|
115
|
+
type: "object",
|
|
116
|
+
properties: {
|
|
117
|
+
messages: {
|
|
118
|
+
type: "array",
|
|
119
|
+
minItems: 1,
|
|
120
|
+
maxItems: 20,
|
|
121
|
+
items: {
|
|
122
|
+
type: "object",
|
|
123
|
+
properties: {
|
|
124
|
+
role: { type: "string", enum: ["user", "assistant"] },
|
|
125
|
+
content: { type: "string", minLength: 1, maxLength: 4e3 }
|
|
126
|
+
},
|
|
127
|
+
required: ["role", "content"],
|
|
128
|
+
additionalProperties: false
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
required: ["messages"],
|
|
133
|
+
additionalProperties: false
|
|
134
|
+
},
|
|
135
|
+
annotations: { readOnlyHint: false },
|
|
136
|
+
execute: async (args, ctx) => {
|
|
137
|
+
if (ctx.config.chatSupport)
|
|
138
|
+
return webMcpError(
|
|
139
|
+
"Der Chat l\xE4uft im Supportmodus mit Anmeldung und ist per Tool nicht verf\xFCgbar. Bitte die Hotline nutzen."
|
|
140
|
+
);
|
|
141
|
+
const messages = parseMessages(args.messages);
|
|
142
|
+
if (typeof messages === "string") return webMcpError(messages);
|
|
143
|
+
try {
|
|
144
|
+
const { answer, responder, sources } = await askChat(
|
|
145
|
+
ctx,
|
|
146
|
+
messages,
|
|
147
|
+
AbortSignal.timeout(9e4)
|
|
148
|
+
);
|
|
149
|
+
return webMcpJson({
|
|
150
|
+
notice: UNTRUSTED_NOTE,
|
|
151
|
+
responder: responder?.role === "on-duty" ? responder.name : "Service-Team",
|
|
152
|
+
answer,
|
|
153
|
+
sources: sources.map((s) => ({
|
|
154
|
+
id: s.id,
|
|
155
|
+
title: s.title,
|
|
156
|
+
href: sourceHref(s.href),
|
|
157
|
+
stale: s.stale ?? false
|
|
158
|
+
}))
|
|
159
|
+
});
|
|
160
|
+
} catch (error) {
|
|
161
|
+
return webMcpError(
|
|
162
|
+
error instanceof Error ? error.message : "Chat nicht verf\xFCgbar."
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
];
|
|
168
|
+
|
|
169
|
+
// src/browser.tsx
|
|
170
|
+
import { useEffect as useEffect2, useLayoutEffect, useRef as useRef2, useState as useState2 } from "react";
|
|
171
|
+
|
|
36
172
|
// src/support-chat.tsx
|
|
37
173
|
import { useEffect, useRef, useState } from "react";
|
|
38
174
|
|
|
@@ -261,7 +397,7 @@ function SupportChat(ctx) {
|
|
|
261
397
|
}
|
|
262
398
|
}
|
|
263
399
|
return /* @__PURE__ */ jsxs("div", { className: "chat-panel support-chat text-ink bg-card border border-line p-6 rounded-card compact:p-4", children: [
|
|
264
|
-
/* @__PURE__ */ jsx("p", { className: "text-[0.75rem] text-ink mb-3", children: demo ? "Synthetische Support-Demo. Keine \xDCbertragung an
|
|
400
|
+
/* @__PURE__ */ jsx("p", { className: "text-[0.75rem] text-ink mb-3", children: demo ? "Synthetische Support-Demo. Keine \xDCbertragung an einen Support-Channel." : `Ihre Nachrichten und die Antworten werden an den Support in ${ctx.config.chatSupport?.mode === "slack" ? "Slack" : "Microsoft Teams"} weitergegeben.` }),
|
|
265
401
|
/* @__PURE__ */ jsxs("p", { role: "status", className: "text-[0.8125rem] mb-3", children: [
|
|
266
402
|
current?.status === "support" ? `${current.support?.name} \xB7 Support` : current?.status === "closed" ? "Gespr\xE4ch abgeschlossen" : "Digitaler Assistent",
|
|
267
403
|
auth && ready && !demo ? ` \xB7 Angemeldet als ${auth.name}` : ""
|
|
@@ -648,6 +784,7 @@ function LegacyChat(ctx) {
|
|
|
648
784
|
var browser_default = {
|
|
649
785
|
id: "chat",
|
|
650
786
|
sdkVersion: cspPlugin.sdkVersion,
|
|
787
|
+
tools: chatTools,
|
|
651
788
|
sections: [
|
|
652
789
|
{
|
|
653
790
|
id: "chat",
|
package/dist/server.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kieksme/csp-plugin-chat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@azure/msal-browser": "^5.25.0",
|
|
26
|
-
"@kieksme/csp-sdk": "^0.
|
|
26
|
+
"@kieksme/csp-sdk": "^0.9.0",
|
|
27
27
|
"openai": "^6.3.0",
|
|
28
28
|
"zod": "^3.25.76"
|
|
29
29
|
},
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"cspPlugin": {
|
|
37
37
|
"id": "chat",
|
|
38
|
-
"sdkVersion": "^0.
|
|
38
|
+
"sdkVersion": "^0.9.0",
|
|
39
39
|
"browser": "./browser",
|
|
40
40
|
"server": "./server"
|
|
41
41
|
},
|