@adminforth/agent 1.46.0 → 1.47.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/build.log +2 -3
- package/chatSurfaceService.ts +52 -110
- package/dist/chatSurfaceService.d.ts +3 -17
- package/dist/chatSurfaceService.js +44 -71
- package/dist/endpoints/chatSurfaces.js +0 -51
- package/dist/endpoints/context.d.ts +2 -6
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -16
- package/dist/types.d.ts +11 -2
- package/endpoints/chatSurfaces.ts +2 -58
- package/endpoints/context.ts +0 -8
- package/index.ts +0 -16
- package/package.json +1 -1
- package/types.ts +11 -2
- package/custom/ChatSurfaceSettings.vue +0 -125
- package/dist/custom/ChatSurfaceSettings.vue +0 -125
package/build.log
CHANGED
|
@@ -7,7 +7,6 @@ custom/
|
|
|
7
7
|
custom/ChatFooter.vue
|
|
8
8
|
custom/ChatHeader.vue
|
|
9
9
|
custom/ChatSurface.vue
|
|
10
|
-
custom/ChatSurfaceSettings.vue
|
|
11
10
|
custom/CustomAutoScrollContainer.vue
|
|
12
11
|
custom/SessionsHistory.vue
|
|
13
12
|
custom/chat.ts
|
|
@@ -63,5 +62,5 @@ custom/speech_recognition_frontend/voiceActivityDetection.ts
|
|
|
63
62
|
custom/speech_recognition_frontend/types/
|
|
64
63
|
custom/speech_recognition_frontend/types/voice-activity-detection.d.ts
|
|
65
64
|
|
|
66
|
-
sent 1,
|
|
67
|
-
total size is 1,
|
|
65
|
+
sent 1,667,665 bytes received 921 bytes 3,337,172.00 bytes/sec
|
|
66
|
+
total size is 1,663,512 speedup is 1.00
|
package/chatSurfaceService.ts
CHANGED
|
@@ -6,23 +6,16 @@ import type {
|
|
|
6
6
|
IAdminForth,
|
|
7
7
|
} from "adminforth";
|
|
8
8
|
import { Filters, logger } from "adminforth";
|
|
9
|
-
import { randomUUID } from "crypto";
|
|
10
9
|
import type { AgentEventEmitter } from "./agentEvents.js";
|
|
11
10
|
import type {
|
|
12
11
|
HandleTurnInput,
|
|
13
12
|
RunAndPersistAgentResponseInput,
|
|
14
13
|
RunAndPersistAgentResponseResult,
|
|
15
14
|
} from "./agentTurnService.js";
|
|
16
|
-
import type { PluginOptions } from "./types.js";
|
|
17
|
-
import type { AgentSessionStore } from "./sessionStore.js";
|
|
18
15
|
import { getErrorMessage, isAbortError } from "./errors.js";
|
|
16
|
+
import type { AgentSessionStore } from "./sessionStore.js";
|
|
19
17
|
import { sanitizeSpeechText } from "./sanitizeSpeechText.js";
|
|
20
|
-
|
|
21
|
-
type ChatSurfaceConnectAction = {
|
|
22
|
-
type: "url";
|
|
23
|
-
label: string;
|
|
24
|
-
url: string;
|
|
25
|
-
};
|
|
18
|
+
import type { PluginOptions } from "./types.js";
|
|
26
19
|
|
|
27
20
|
type ChatSurfaceIncomingMessageWithAudio = ChatSurfaceIncomingMessage & {
|
|
28
21
|
audio?: {
|
|
@@ -41,24 +34,7 @@ type ChatSurfaceEventSinkWithAudio = ChatSurfaceEventSink & {
|
|
|
41
34
|
}): void | Promise<void>;
|
|
42
35
|
};
|
|
43
36
|
|
|
44
|
-
export type ChatSurfaceAdapterWithConnectAction = ChatSurfaceAdapter & {
|
|
45
|
-
createConnectAction?(input: {
|
|
46
|
-
token: string;
|
|
47
|
-
}): ChatSurfaceConnectAction | Promise<ChatSurfaceConnectAction>;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
type ChatSurfaceLinkTokenPayload = {
|
|
51
|
-
surface: string;
|
|
52
|
-
adminUserId: AdminUser["pk"];
|
|
53
|
-
expiresAt: number;
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const DEFAULT_ADMIN_USER_EXTERNAL_USER_ID_FIELD = "externalUserId";
|
|
57
|
-
const CHAT_SURFACE_LINK_TOKEN_TTL_MS = 60 * 1000;
|
|
58
|
-
|
|
59
37
|
export class ChatSurfaceService {
|
|
60
|
-
private linkTokens = new Map<string, ChatSurfaceLinkTokenPayload>();
|
|
61
|
-
|
|
62
38
|
constructor(
|
|
63
39
|
private getAdminforth: () => IAdminForth,
|
|
64
40
|
private options: PluginOptions,
|
|
@@ -69,40 +45,6 @@ export class ChatSurfaceService {
|
|
|
69
45
|
) => Promise<RunAndPersistAgentResponseResult>,
|
|
70
46
|
) {}
|
|
71
47
|
|
|
72
|
-
getConnectActionAdapters() {
|
|
73
|
-
return (this.options.chatSurfaceAdapters ?? [])
|
|
74
|
-
.map((adapter) => adapter as ChatSurfaceAdapterWithConnectAction)
|
|
75
|
-
.filter((adapter) => adapter.createConnectAction);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
createLinkToken(surface: string, adminUser: AdminUser) {
|
|
79
|
-
for (const [token, payload] of this.linkTokens) {
|
|
80
|
-
if (payload.expiresAt <= Date.now()) {
|
|
81
|
-
this.linkTokens.delete(token);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const token = randomUUID();
|
|
86
|
-
this.linkTokens.set(token, {
|
|
87
|
-
surface,
|
|
88
|
-
adminUserId: adminUser.pk,
|
|
89
|
-
expiresAt: Date.now() + CHAT_SURFACE_LINK_TOKEN_TTL_MS,
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
return token;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
private consumeLinkToken(surface: string, token: string) {
|
|
96
|
-
const payload = this.linkTokens.get(token);
|
|
97
|
-
this.linkTokens.delete(token);
|
|
98
|
-
|
|
99
|
-
if (!payload || payload.surface !== surface || payload.expiresAt <= Date.now()) {
|
|
100
|
-
return null;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return payload;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
48
|
private createEventEmitter(sink: ChatSurfaceEventSink): AgentEventEmitter {
|
|
107
49
|
return async (event) => {
|
|
108
50
|
if (event.type === "text-delta") {
|
|
@@ -138,55 +80,10 @@ export class ChatSurfaceService {
|
|
|
138
80
|
return false;
|
|
139
81
|
}
|
|
140
82
|
|
|
141
|
-
const externalUserIdField = this.options.chatExternalIdsField ?? DEFAULT_ADMIN_USER_EXTERNAL_USER_ID_FIELD;
|
|
142
|
-
const adminforth = this.getAdminforth();
|
|
143
|
-
const authResourceId = adminforth.config.auth!.usersResourceId!;
|
|
144
|
-
const authResource = adminforth.config.resources.find((resource) => resource.resourceId === authResourceId)!;
|
|
145
|
-
const primaryKeyField = authResource.columns.find((column) => column.primaryKey)!.name!;
|
|
146
|
-
const linkedAdminUserRecord = (
|
|
147
|
-
await adminforth.resource(authResourceId).list(Filters.IS_NOT_EMPTY(externalUserIdField))
|
|
148
|
-
).find((user) => user[externalUserIdField]?.[incoming.surface] === incoming.externalUserId);
|
|
149
|
-
|
|
150
|
-
if (linkedAdminUserRecord) {
|
|
151
|
-
await sink.emit({
|
|
152
|
-
type: "done",
|
|
153
|
-
text: `${incoming.surface} account is already connected to AdminForth.`,
|
|
154
|
-
});
|
|
155
|
-
return true;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (typeof incoming.metadata?.startPayload !== "string") {
|
|
159
|
-
await sink.emit({
|
|
160
|
-
type: "done",
|
|
161
|
-
text: `Open AdminForth and connect your ${incoming.surface} account from Chat Surfaces settings.`,
|
|
162
|
-
});
|
|
163
|
-
return true;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const payload = this.consumeLinkToken(incoming.surface, incoming.metadata.startPayload);
|
|
167
|
-
if (!payload) {
|
|
168
|
-
await sink.emit({
|
|
169
|
-
type: "error",
|
|
170
|
-
message: "This chat surface link is expired or invalid. Please start linking again from AdminForth.",
|
|
171
|
-
});
|
|
172
|
-
return true;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const adminUserRecord = await adminforth.resource(authResourceId).get([
|
|
176
|
-
Filters.EQ(primaryKeyField, payload.adminUserId),
|
|
177
|
-
]);
|
|
178
|
-
|
|
179
|
-
await adminforth.resource(authResourceId).update(payload.adminUserId, {
|
|
180
|
-
[externalUserIdField]: {
|
|
181
|
-
...(adminUserRecord[externalUserIdField] ?? {}),
|
|
182
|
-
[incoming.surface]: incoming.externalUserId,
|
|
183
|
-
},
|
|
184
|
-
});
|
|
185
83
|
await sink.emit({
|
|
186
84
|
type: "done",
|
|
187
|
-
text:
|
|
85
|
+
text: `Open AdminForth and connect your ${incoming.surface} account from Connected Accounts settings.`,
|
|
188
86
|
});
|
|
189
|
-
|
|
190
87
|
return true;
|
|
191
88
|
}
|
|
192
89
|
|
|
@@ -327,6 +224,54 @@ export class ChatSurfaceService {
|
|
|
327
224
|
return agentResponse;
|
|
328
225
|
}
|
|
329
226
|
|
|
227
|
+
private async getAdminUserRecordForChatSurface(
|
|
228
|
+
adapter: ChatSurfaceAdapter,
|
|
229
|
+
incoming: ChatSurfaceIncomingMessage,
|
|
230
|
+
) {
|
|
231
|
+
const adminforth = this.getAdminforth();
|
|
232
|
+
const authResourceId = adminforth.config.auth!.usersResourceId!;
|
|
233
|
+
const externalIdentityResource = this.options.chatExternalIdentityResource;
|
|
234
|
+
if (!externalIdentityResource) {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const surfaceIdentityConfig = externalIdentityResource.surfaces[adapter.name];
|
|
239
|
+
if (!surfaceIdentityConfig) {
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const providerField = externalIdentityResource.providerField ?? 'provider';
|
|
244
|
+
const subjectField = externalIdentityResource.subjectField ?? 'subject';
|
|
245
|
+
const adminUserIdField = externalIdentityResource.adminUserIdField ?? 'adminUserId';
|
|
246
|
+
const externalUserIdField = externalIdentityResource.externalUserIdField ?? 'externalUserId';
|
|
247
|
+
const identityFilters = [
|
|
248
|
+
Filters.EQ(providerField, surfaceIdentityConfig.provider),
|
|
249
|
+
Filters.EQ(externalUserIdField, incoming.externalUserId),
|
|
250
|
+
];
|
|
251
|
+
const identities = await adminforth.resource(externalIdentityResource.resourceId).list(identityFilters);
|
|
252
|
+
const identity = identities.find((identity) => {
|
|
253
|
+
if (String(identity[externalUserIdField]) === incoming.externalUserId) {
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (String(identity[subjectField]) === incoming.externalUserId) {
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return false;
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
if (!identity) {
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const authResource = adminforth.config.resources.find((resource) => resource.resourceId === authResourceId)!;
|
|
269
|
+
const primaryKeyField = authResource.columns.find((column) => column.primaryKey)!.name!;
|
|
270
|
+
return adminforth.resource(authResourceId).get([
|
|
271
|
+
Filters.EQ(primaryKeyField, identity[adminUserIdField]),
|
|
272
|
+
]);
|
|
273
|
+
}
|
|
274
|
+
|
|
330
275
|
async handleMessage(
|
|
331
276
|
adapter: ChatSurfaceAdapter,
|
|
332
277
|
incoming: ChatSurfaceIncomingMessage,
|
|
@@ -340,10 +285,7 @@ export class ChatSurfaceService {
|
|
|
340
285
|
const authResourceId = adminforth.config.auth!.usersResourceId!;
|
|
341
286
|
const authResource = adminforth.config.resources.find((resource) => resource.resourceId === authResourceId)!;
|
|
342
287
|
const primaryKeyField = authResource.columns.find((column) => column.primaryKey)!.name!;
|
|
343
|
-
const
|
|
344
|
-
const adminUserRecord = (
|
|
345
|
-
await adminforth.resource(authResourceId).list(Filters.IS_NOT_EMPTY(externalUserIdField))
|
|
346
|
-
).find((user) => user[externalUserIdField]?.[adapter.name] === incoming.externalUserId);
|
|
288
|
+
const adminUserRecord = await this.getAdminUserRecordForChatSurface(adapter, incoming);
|
|
347
289
|
|
|
348
290
|
if (!adminUserRecord) {
|
|
349
291
|
await sink.emit({
|
|
@@ -1,32 +1,18 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ChatSurfaceAdapter, ChatSurfaceEventSink, ChatSurfaceIncomingMessage, IAdminForth } from "adminforth";
|
|
2
2
|
import type { HandleTurnInput, RunAndPersistAgentResponseInput, RunAndPersistAgentResponseResult } from "./agentTurnService.js";
|
|
3
|
-
import type { PluginOptions } from "./types.js";
|
|
4
3
|
import type { AgentSessionStore } from "./sessionStore.js";
|
|
5
|
-
type
|
|
6
|
-
type: "url";
|
|
7
|
-
label: string;
|
|
8
|
-
url: string;
|
|
9
|
-
};
|
|
10
|
-
export type ChatSurfaceAdapterWithConnectAction = ChatSurfaceAdapter & {
|
|
11
|
-
createConnectAction?(input: {
|
|
12
|
-
token: string;
|
|
13
|
-
}): ChatSurfaceConnectAction | Promise<ChatSurfaceConnectAction>;
|
|
14
|
-
};
|
|
4
|
+
import type { PluginOptions } from "./types.js";
|
|
15
5
|
export declare class ChatSurfaceService {
|
|
16
6
|
private getAdminforth;
|
|
17
7
|
private options;
|
|
18
8
|
private sessionStore;
|
|
19
9
|
private handleTurn;
|
|
20
10
|
private runAndPersistAgentResponse;
|
|
21
|
-
private linkTokens;
|
|
22
11
|
constructor(getAdminforth: () => IAdminForth, options: PluginOptions, sessionStore: AgentSessionStore, handleTurn: (input: HandleTurnInput) => Promise<unknown>, runAndPersistAgentResponse: (input: RunAndPersistAgentResponseInput) => Promise<RunAndPersistAgentResponseResult>);
|
|
23
|
-
getConnectActionAdapters(): ChatSurfaceAdapterWithConnectAction[];
|
|
24
|
-
createLinkToken(surface: string, adminUser: AdminUser): `${string}-${string}-${string}-${string}-${string}`;
|
|
25
|
-
private consumeLinkToken;
|
|
26
12
|
private createEventEmitter;
|
|
27
13
|
private handleLink;
|
|
28
14
|
private handleAudioMessage;
|
|
29
15
|
private handleAgentSurfaceResponse;
|
|
16
|
+
private getAdminUserRecordForChatSurface;
|
|
30
17
|
handleMessage(adapter: ChatSurfaceAdapter, incoming: ChatSurfaceIncomingMessage, sink: ChatSurfaceEventSink): Promise<void>;
|
|
31
18
|
}
|
|
32
|
-
export {};
|
|
@@ -8,11 +8,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { Filters, logger } from "adminforth";
|
|
11
|
-
import { randomUUID } from "crypto";
|
|
12
11
|
import { getErrorMessage, isAbortError } from "./errors.js";
|
|
13
12
|
import { sanitizeSpeechText } from "./sanitizeSpeechText.js";
|
|
14
|
-
const DEFAULT_ADMIN_USER_EXTERNAL_USER_ID_FIELD = "externalUserId";
|
|
15
|
-
const CHAT_SURFACE_LINK_TOKEN_TTL_MS = 60 * 1000;
|
|
16
13
|
export class ChatSurfaceService {
|
|
17
14
|
constructor(getAdminforth, options, sessionStore, handleTurn, runAndPersistAgentResponse) {
|
|
18
15
|
this.getAdminforth = getAdminforth;
|
|
@@ -20,35 +17,6 @@ export class ChatSurfaceService {
|
|
|
20
17
|
this.sessionStore = sessionStore;
|
|
21
18
|
this.handleTurn = handleTurn;
|
|
22
19
|
this.runAndPersistAgentResponse = runAndPersistAgentResponse;
|
|
23
|
-
this.linkTokens = new Map();
|
|
24
|
-
}
|
|
25
|
-
getConnectActionAdapters() {
|
|
26
|
-
var _a;
|
|
27
|
-
return ((_a = this.options.chatSurfaceAdapters) !== null && _a !== void 0 ? _a : [])
|
|
28
|
-
.map((adapter) => adapter)
|
|
29
|
-
.filter((adapter) => adapter.createConnectAction);
|
|
30
|
-
}
|
|
31
|
-
createLinkToken(surface, adminUser) {
|
|
32
|
-
for (const [token, payload] of this.linkTokens) {
|
|
33
|
-
if (payload.expiresAt <= Date.now()) {
|
|
34
|
-
this.linkTokens.delete(token);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
const token = randomUUID();
|
|
38
|
-
this.linkTokens.set(token, {
|
|
39
|
-
surface,
|
|
40
|
-
adminUserId: adminUser.pk,
|
|
41
|
-
expiresAt: Date.now() + CHAT_SURFACE_LINK_TOKEN_TTL_MS,
|
|
42
|
-
});
|
|
43
|
-
return token;
|
|
44
|
-
}
|
|
45
|
-
consumeLinkToken(surface, token) {
|
|
46
|
-
const payload = this.linkTokens.get(token);
|
|
47
|
-
this.linkTokens.delete(token);
|
|
48
|
-
if (!payload || payload.surface !== surface || payload.expiresAt <= Date.now()) {
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
return payload;
|
|
52
20
|
}
|
|
53
21
|
createEventEmitter(sink) {
|
|
54
22
|
return (event) => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -76,47 +44,13 @@ export class ChatSurfaceService {
|
|
|
76
44
|
}
|
|
77
45
|
handleLink(incoming, sink) {
|
|
78
46
|
return __awaiter(this, void 0, void 0, function* () {
|
|
79
|
-
var _a
|
|
47
|
+
var _a;
|
|
80
48
|
if (((_a = incoming.metadata) === null || _a === void 0 ? void 0 : _a.isStartCommand) !== true) {
|
|
81
49
|
return false;
|
|
82
50
|
}
|
|
83
|
-
const externalUserIdField = (_b = this.options.chatExternalIdsField) !== null && _b !== void 0 ? _b : DEFAULT_ADMIN_USER_EXTERNAL_USER_ID_FIELD;
|
|
84
|
-
const adminforth = this.getAdminforth();
|
|
85
|
-
const authResourceId = adminforth.config.auth.usersResourceId;
|
|
86
|
-
const authResource = adminforth.config.resources.find((resource) => resource.resourceId === authResourceId);
|
|
87
|
-
const primaryKeyField = authResource.columns.find((column) => column.primaryKey).name;
|
|
88
|
-
const linkedAdminUserRecord = (yield adminforth.resource(authResourceId).list(Filters.IS_NOT_EMPTY(externalUserIdField))).find((user) => { var _a; return ((_a = user[externalUserIdField]) === null || _a === void 0 ? void 0 : _a[incoming.surface]) === incoming.externalUserId; });
|
|
89
|
-
if (linkedAdminUserRecord) {
|
|
90
|
-
yield sink.emit({
|
|
91
|
-
type: "done",
|
|
92
|
-
text: `${incoming.surface} account is already connected to AdminForth.`,
|
|
93
|
-
});
|
|
94
|
-
return true;
|
|
95
|
-
}
|
|
96
|
-
if (typeof ((_c = incoming.metadata) === null || _c === void 0 ? void 0 : _c.startPayload) !== "string") {
|
|
97
|
-
yield sink.emit({
|
|
98
|
-
type: "done",
|
|
99
|
-
text: `Open AdminForth and connect your ${incoming.surface} account from Chat Surfaces settings.`,
|
|
100
|
-
});
|
|
101
|
-
return true;
|
|
102
|
-
}
|
|
103
|
-
const payload = this.consumeLinkToken(incoming.surface, incoming.metadata.startPayload);
|
|
104
|
-
if (!payload) {
|
|
105
|
-
yield sink.emit({
|
|
106
|
-
type: "error",
|
|
107
|
-
message: "This chat surface link is expired or invalid. Please start linking again from AdminForth.",
|
|
108
|
-
});
|
|
109
|
-
return true;
|
|
110
|
-
}
|
|
111
|
-
const adminUserRecord = yield adminforth.resource(authResourceId).get([
|
|
112
|
-
Filters.EQ(primaryKeyField, payload.adminUserId),
|
|
113
|
-
]);
|
|
114
|
-
yield adminforth.resource(authResourceId).update(payload.adminUserId, {
|
|
115
|
-
[externalUserIdField]: Object.assign(Object.assign({}, ((_d = adminUserRecord[externalUserIdField]) !== null && _d !== void 0 ? _d : {})), { [incoming.surface]: incoming.externalUserId }),
|
|
116
|
-
});
|
|
117
51
|
yield sink.emit({
|
|
118
52
|
type: "done",
|
|
119
|
-
text:
|
|
53
|
+
text: `Open AdminForth and connect your ${incoming.surface} account from Connected Accounts settings.`,
|
|
120
54
|
});
|
|
121
55
|
return true;
|
|
122
56
|
});
|
|
@@ -230,9 +164,49 @@ export class ChatSurfaceService {
|
|
|
230
164
|
return agentResponse;
|
|
231
165
|
});
|
|
232
166
|
}
|
|
167
|
+
getAdminUserRecordForChatSurface(adapter, incoming) {
|
|
168
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
169
|
+
var _a, _b, _c, _d;
|
|
170
|
+
const adminforth = this.getAdminforth();
|
|
171
|
+
const authResourceId = adminforth.config.auth.usersResourceId;
|
|
172
|
+
const externalIdentityResource = this.options.chatExternalIdentityResource;
|
|
173
|
+
if (!externalIdentityResource) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
const surfaceIdentityConfig = externalIdentityResource.surfaces[adapter.name];
|
|
177
|
+
if (!surfaceIdentityConfig) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
const providerField = (_a = externalIdentityResource.providerField) !== null && _a !== void 0 ? _a : 'provider';
|
|
181
|
+
const subjectField = (_b = externalIdentityResource.subjectField) !== null && _b !== void 0 ? _b : 'subject';
|
|
182
|
+
const adminUserIdField = (_c = externalIdentityResource.adminUserIdField) !== null && _c !== void 0 ? _c : 'adminUserId';
|
|
183
|
+
const externalUserIdField = (_d = externalIdentityResource.externalUserIdField) !== null && _d !== void 0 ? _d : 'externalUserId';
|
|
184
|
+
const identityFilters = [
|
|
185
|
+
Filters.EQ(providerField, surfaceIdentityConfig.provider),
|
|
186
|
+
Filters.EQ(externalUserIdField, incoming.externalUserId),
|
|
187
|
+
];
|
|
188
|
+
const identities = yield adminforth.resource(externalIdentityResource.resourceId).list(identityFilters);
|
|
189
|
+
const identity = identities.find((identity) => {
|
|
190
|
+
if (String(identity[externalUserIdField]) === incoming.externalUserId) {
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
if (String(identity[subjectField]) === incoming.externalUserId) {
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
return false;
|
|
197
|
+
});
|
|
198
|
+
if (!identity) {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
const authResource = adminforth.config.resources.find((resource) => resource.resourceId === authResourceId);
|
|
202
|
+
const primaryKeyField = authResource.columns.find((column) => column.primaryKey).name;
|
|
203
|
+
return adminforth.resource(authResourceId).get([
|
|
204
|
+
Filters.EQ(primaryKeyField, identity[adminUserIdField]),
|
|
205
|
+
]);
|
|
206
|
+
});
|
|
207
|
+
}
|
|
233
208
|
handleMessage(adapter, incoming, sink) {
|
|
234
209
|
return __awaiter(this, void 0, void 0, function* () {
|
|
235
|
-
var _a;
|
|
236
210
|
if (yield this.handleLink(incoming, sink)) {
|
|
237
211
|
return;
|
|
238
212
|
}
|
|
@@ -240,8 +214,7 @@ export class ChatSurfaceService {
|
|
|
240
214
|
const authResourceId = adminforth.config.auth.usersResourceId;
|
|
241
215
|
const authResource = adminforth.config.resources.find((resource) => resource.resourceId === authResourceId);
|
|
242
216
|
const primaryKeyField = authResource.columns.find((column) => column.primaryKey).name;
|
|
243
|
-
const
|
|
244
|
-
const adminUserRecord = (yield adminforth.resource(authResourceId).list(Filters.IS_NOT_EMPTY(externalUserIdField))).find((user) => { var _a; return ((_a = user[externalUserIdField]) === null || _a === void 0 ? void 0 : _a[adapter.name]) === incoming.externalUserId; });
|
|
217
|
+
const adminUserRecord = yield this.getAdminUserRecordForChatSurface(adapter, incoming);
|
|
245
218
|
if (!adminUserRecord) {
|
|
246
219
|
yield sink.emit({
|
|
247
220
|
type: "error",
|
|
@@ -7,60 +7,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
const DEFAULT_ADMIN_USER_EXTERNAL_USER_ID_FIELD = "externalUserId";
|
|
11
10
|
export function setupChatSurfaceEndpoints(ctx, server) {
|
|
12
11
|
var _a;
|
|
13
|
-
if (ctx.getChatSurfaceConnectActionAdapters().length) {
|
|
14
|
-
server.endpoint({
|
|
15
|
-
method: "POST",
|
|
16
|
-
path: "/agent/surfaces/connectable",
|
|
17
|
-
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ adminUser }) {
|
|
18
|
-
var _b, _c;
|
|
19
|
-
const externalUserIdField = (_b = ctx.options.chatExternalIdsField) !== null && _b !== void 0 ? _b : DEFAULT_ADMIN_USER_EXTERNAL_USER_ID_FIELD;
|
|
20
|
-
const externalIds = (_c = adminUser.dbUser[externalUserIdField]) !== null && _c !== void 0 ? _c : {};
|
|
21
|
-
return {
|
|
22
|
-
surfaces: ctx.getChatSurfaceConnectActionAdapters().map((adapter) => {
|
|
23
|
-
var _a;
|
|
24
|
-
return ({
|
|
25
|
-
name: adapter.name,
|
|
26
|
-
externalUserId: (_a = externalIds[adapter.name]) !== null && _a !== void 0 ? _a : null,
|
|
27
|
-
});
|
|
28
|
-
}),
|
|
29
|
-
};
|
|
30
|
-
}),
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
12
|
for (const adapter of (_a = ctx.options.chatSurfaceAdapters) !== null && _a !== void 0 ? _a : []) {
|
|
34
|
-
const connectActionAdapter = adapter;
|
|
35
|
-
if (connectActionAdapter.createConnectAction) {
|
|
36
|
-
server.endpoint({
|
|
37
|
-
method: "POST",
|
|
38
|
-
path: `/agent/surface/${adapter.name}/connect-action`,
|
|
39
|
-
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ adminUser }) {
|
|
40
|
-
const token = ctx.createChatSurfaceLinkToken(adapter.name, adminUser);
|
|
41
|
-
const action = yield connectActionAdapter.createConnectAction({ token });
|
|
42
|
-
return {
|
|
43
|
-
action,
|
|
44
|
-
};
|
|
45
|
-
}),
|
|
46
|
-
});
|
|
47
|
-
server.endpoint({
|
|
48
|
-
method: "POST",
|
|
49
|
-
path: `/agent/surface/${adapter.name}/disconnect`,
|
|
50
|
-
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ adminUser }) {
|
|
51
|
-
var _b, _c;
|
|
52
|
-
const externalUserIdField = (_b = ctx.options.chatExternalIdsField) !== null && _b !== void 0 ? _b : DEFAULT_ADMIN_USER_EXTERNAL_USER_ID_FIELD;
|
|
53
|
-
const externalIds = Object.assign({}, ((_c = adminUser.dbUser[externalUserIdField]) !== null && _c !== void 0 ? _c : {}));
|
|
54
|
-
delete externalIds[adapter.name];
|
|
55
|
-
yield ctx.adminforth.resource(ctx.adminforth.config.auth.usersResourceId).update(adminUser.pk, {
|
|
56
|
-
[externalUserIdField]: externalIds,
|
|
57
|
-
});
|
|
58
|
-
return {
|
|
59
|
-
ok: true,
|
|
60
|
-
};
|
|
61
|
-
}),
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
13
|
server.endpoint({
|
|
65
14
|
method: "POST",
|
|
66
15
|
noAuth: true,
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ChatSurfaceAdapter, ChatSurfaceEventSink, ChatSurfaceIncomingMessage, IAdminForth } from "adminforth";
|
|
2
2
|
import type { ZodType } from "zod";
|
|
3
3
|
import type { HandleSpeechTurnInput, HandleTurnInput, RunAndPersistAgentResponseInput, RunAndPersistAgentResponseResult } from "../agentTurnService.js";
|
|
4
|
-
import type { ChatSurfaceAdapterWithConnectAction } from "../chatSurfaceService.js";
|
|
5
4
|
import type { PluginOptions } from "../types.js";
|
|
6
|
-
export type { ChatSurfaceAdapterWithConnectAction } from "../chatSurfaceService.js";
|
|
7
5
|
export type EndpointResponse = {
|
|
8
6
|
setStatus: (code: number, message: string) => void;
|
|
9
7
|
};
|
|
@@ -21,10 +19,8 @@ export type AgentEndpointsContext = {
|
|
|
21
19
|
getSessionTurns(sessionId: string): Promise<SessionTurn[]>;
|
|
22
20
|
createNewTurn(sessionId: string, prompt: string, response?: string): Promise<string>;
|
|
23
21
|
createSystemTurn(sessionId: string, systemMessage: string): Promise<string>;
|
|
24
|
-
getChatSurfaceConnectActionAdapters(): ChatSurfaceAdapterWithConnectAction[];
|
|
25
|
-
createChatSurfaceLinkToken(surface: string, adminUser: AdminUser): string;
|
|
26
22
|
handleChatSurfaceMessage(adapter: ChatSurfaceAdapter, incoming: ChatSurfaceIncomingMessage, sink: ChatSurfaceEventSink): Promise<void>;
|
|
27
23
|
};
|
|
28
24
|
export type CoreEndpointsContext = Pick<AgentEndpointsContext, "options" | "parseBody" | "handleTurn" | "handleSpeechTurn">;
|
|
29
25
|
export type SessionEndpointsContext = Pick<AgentEndpointsContext, "adminforth" | "options" | "parseBody" | "getSessionTurns" | "createNewTurn" | "createSystemTurn">;
|
|
30
|
-
export type ChatSurfaceEndpointsContext = Pick<AgentEndpointsContext, "adminforth" | "options" | "
|
|
26
|
+
export type ChatSurfaceEndpointsContext = Pick<AgentEndpointsContext, "adminforth" | "options" | "handleChatSurfaceMessage">;
|
package/dist/index.d.ts
CHANGED
|
@@ -9,7 +9,6 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
9
9
|
private sessionStore;
|
|
10
10
|
private agentTurnService;
|
|
11
11
|
private chatSurfaceService;
|
|
12
|
-
private chatSurfaceSettingsPageRegistered;
|
|
13
12
|
private parseBody;
|
|
14
13
|
private getCheckpointer;
|
|
15
14
|
private getInternalAgentResourceIds;
|
package/dist/index.js
CHANGED
|
@@ -45,7 +45,6 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
45
45
|
constructor(options) {
|
|
46
46
|
super(options, import.meta.url);
|
|
47
47
|
this.checkpointer = null;
|
|
48
|
-
this.chatSurfaceSettingsPageRegistered = false;
|
|
49
48
|
this.options = options;
|
|
50
49
|
this.sessionStore = new AgentSessionStore(() => this.adminforth, this.options);
|
|
51
50
|
this.agentTurnService = new AgentTurnService({
|
|
@@ -84,19 +83,6 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
84
83
|
hasAudioAdapter: Boolean(this.options.audioAdapter),
|
|
85
84
|
}
|
|
86
85
|
});
|
|
87
|
-
if (this.chatSurfaceService.getConnectActionAdapters().length && !this.chatSurfaceSettingsPageRegistered) {
|
|
88
|
-
if (!this.adminforth.config.auth.userMenuSettingsPages) {
|
|
89
|
-
this.adminforth.config.auth.userMenuSettingsPages = [];
|
|
90
|
-
}
|
|
91
|
-
this.adminforth.config.auth.userMenuSettingsPages.push({
|
|
92
|
-
icon: "flowbite:link-outline",
|
|
93
|
-
pageLabel: "Chat Surfaces",
|
|
94
|
-
slug: "chat-surfaces",
|
|
95
|
-
component: this.componentPath("ChatSurfaceSettings.vue"),
|
|
96
|
-
isVisible: () => true,
|
|
97
|
-
});
|
|
98
|
-
this.chatSurfaceSettingsPageRegistered = true;
|
|
99
|
-
}
|
|
100
86
|
if (!this.adminforth.config.customization.customHeadItems) {
|
|
101
87
|
this.adminforth.config.customization.customHeadItems = [];
|
|
102
88
|
}
|
|
@@ -139,8 +125,6 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
139
125
|
getSessionTurns: this.sessionStore.getSessionTurns.bind(this.sessionStore),
|
|
140
126
|
createNewTurn: this.sessionStore.createNewTurn.bind(this.sessionStore),
|
|
141
127
|
createSystemTurn: this.sessionStore.createSystemTurn.bind(this.sessionStore),
|
|
142
|
-
getChatSurfaceConnectActionAdapters: this.chatSurfaceService.getConnectActionAdapters.bind(this.chatSurfaceService),
|
|
143
|
-
createChatSurfaceLinkToken: this.chatSurfaceService.createLinkToken.bind(this.chatSurfaceService),
|
|
144
128
|
handleChatSurfaceMessage: this.chatSurfaceService.handleMessage.bind(this.chatSurfaceService),
|
|
145
129
|
};
|
|
146
130
|
setupCoreEndpoints(endpointContext, server);
|
package/dist/types.d.ts
CHANGED
|
@@ -91,8 +91,17 @@ export interface PluginOptions extends PluginsCommonOptions {
|
|
|
91
91
|
*/
|
|
92
92
|
checkpointResource?: ICheckpointResource;
|
|
93
93
|
/**
|
|
94
|
-
* Optional
|
|
94
|
+
* Optional resource configuration for resolving chat users through OAuth external identities.
|
|
95
95
|
*/
|
|
96
|
-
|
|
96
|
+
chatExternalIdentityResource?: {
|
|
97
|
+
resourceId: string;
|
|
98
|
+
adminUserIdField?: string;
|
|
99
|
+
providerField?: string;
|
|
100
|
+
subjectField?: string;
|
|
101
|
+
externalUserIdField?: string;
|
|
102
|
+
surfaces: Record<string, {
|
|
103
|
+
provider: string;
|
|
104
|
+
}>;
|
|
105
|
+
};
|
|
97
106
|
}
|
|
98
107
|
export {};
|
|
@@ -2,66 +2,10 @@ import type {
|
|
|
2
2
|
IAdminForthEndpointHandlerInput,
|
|
3
3
|
IHttpServer,
|
|
4
4
|
} from "adminforth";
|
|
5
|
-
import type {
|
|
6
|
-
|
|
7
|
-
const DEFAULT_ADMIN_USER_EXTERNAL_USER_ID_FIELD = "externalUserId";
|
|
5
|
+
import type { ChatSurfaceEndpointsContext } from "./context.js";
|
|
8
6
|
|
|
9
7
|
export function setupChatSurfaceEndpoints(ctx: ChatSurfaceEndpointsContext, server: IHttpServer) {
|
|
10
|
-
if (ctx.getChatSurfaceConnectActionAdapters().length) {
|
|
11
|
-
server.endpoint({
|
|
12
|
-
method: "POST",
|
|
13
|
-
path: "/agent/surfaces/connectable",
|
|
14
|
-
handler: async ({ adminUser }) => {
|
|
15
|
-
const externalUserIdField = ctx.options.chatExternalIdsField ?? DEFAULT_ADMIN_USER_EXTERNAL_USER_ID_FIELD;
|
|
16
|
-
const externalIds = adminUser!.dbUser[externalUserIdField] ?? {};
|
|
17
|
-
|
|
18
|
-
return {
|
|
19
|
-
surfaces: ctx.getChatSurfaceConnectActionAdapters().map((adapter) => ({
|
|
20
|
-
name: adapter.name,
|
|
21
|
-
externalUserId: externalIds[adapter.name] ?? null,
|
|
22
|
-
})),
|
|
23
|
-
};
|
|
24
|
-
},
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
8
|
for (const adapter of ctx.options.chatSurfaceAdapters ?? []) {
|
|
29
|
-
const connectActionAdapter = adapter as ChatSurfaceAdapterWithConnectAction;
|
|
30
|
-
if (connectActionAdapter.createConnectAction) {
|
|
31
|
-
server.endpoint({
|
|
32
|
-
method: "POST",
|
|
33
|
-
path: `/agent/surface/${adapter.name}/connect-action`,
|
|
34
|
-
handler: async ({ adminUser }) => {
|
|
35
|
-
const token = ctx.createChatSurfaceLinkToken(adapter.name, adminUser!);
|
|
36
|
-
const action = await connectActionAdapter.createConnectAction!({ token });
|
|
37
|
-
|
|
38
|
-
return {
|
|
39
|
-
action,
|
|
40
|
-
};
|
|
41
|
-
},
|
|
42
|
-
});
|
|
43
|
-
server.endpoint({
|
|
44
|
-
method: "POST",
|
|
45
|
-
path: `/agent/surface/${adapter.name}/disconnect`,
|
|
46
|
-
handler: async ({ adminUser }) => {
|
|
47
|
-
const externalUserIdField = ctx.options.chatExternalIdsField ?? DEFAULT_ADMIN_USER_EXTERNAL_USER_ID_FIELD;
|
|
48
|
-
const externalIds = {
|
|
49
|
-
...(adminUser!.dbUser[externalUserIdField] ?? {}),
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
delete externalIds[adapter.name];
|
|
53
|
-
|
|
54
|
-
await ctx.adminforth.resource(ctx.adminforth.config.auth!.usersResourceId!).update(adminUser!.pk, {
|
|
55
|
-
[externalUserIdField]: externalIds,
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
return {
|
|
59
|
-
ok: true,
|
|
60
|
-
};
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
|
|
65
9
|
server.endpoint({
|
|
66
10
|
method: "POST",
|
|
67
11
|
noAuth: true,
|
|
@@ -74,8 +18,8 @@ export function setupChatSurfaceEndpoints(ctx: ChatSurfaceEndpointsContext, serv
|
|
|
74
18
|
rawRequest: endpointInput._raw_express_req,
|
|
75
19
|
rawResponse: endpointInput._raw_express_res,
|
|
76
20
|
};
|
|
77
|
-
const incoming = await adapter.parseIncomingMessage(surfaceContext);
|
|
78
21
|
|
|
22
|
+
const incoming = await adapter.parseIncomingMessage(surfaceContext);
|
|
79
23
|
if (!incoming) return { ok: true };
|
|
80
24
|
|
|
81
25
|
const sink = await adapter.createEventSink(surfaceContext, incoming);
|
package/endpoints/context.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
AdminUser,
|
|
3
2
|
ChatSurfaceAdapter,
|
|
4
3
|
ChatSurfaceEventSink,
|
|
5
4
|
ChatSurfaceIncomingMessage,
|
|
@@ -12,11 +11,8 @@ import type {
|
|
|
12
11
|
RunAndPersistAgentResponseInput,
|
|
13
12
|
RunAndPersistAgentResponseResult,
|
|
14
13
|
} from "../agentTurnService.js";
|
|
15
|
-
import type { ChatSurfaceAdapterWithConnectAction } from "../chatSurfaceService.js";
|
|
16
14
|
import type { PluginOptions } from "../types.js";
|
|
17
15
|
|
|
18
|
-
export type { ChatSurfaceAdapterWithConnectAction } from "../chatSurfaceService.js";
|
|
19
|
-
|
|
20
16
|
export type EndpointResponse = {
|
|
21
17
|
setStatus: (code: number, message: string) => void;
|
|
22
18
|
};
|
|
@@ -36,8 +32,6 @@ export type AgentEndpointsContext = {
|
|
|
36
32
|
getSessionTurns(sessionId: string): Promise<SessionTurn[]>;
|
|
37
33
|
createNewTurn(sessionId: string, prompt: string, response?: string): Promise<string>;
|
|
38
34
|
createSystemTurn(sessionId: string, systemMessage: string): Promise<string>;
|
|
39
|
-
getChatSurfaceConnectActionAdapters(): ChatSurfaceAdapterWithConnectAction[];
|
|
40
|
-
createChatSurfaceLinkToken(surface: string, adminUser: AdminUser): string;
|
|
41
35
|
handleChatSurfaceMessage(
|
|
42
36
|
adapter: ChatSurfaceAdapter,
|
|
43
37
|
incoming: ChatSurfaceIncomingMessage,
|
|
@@ -60,7 +54,5 @@ export type ChatSurfaceEndpointsContext = Pick<
|
|
|
60
54
|
AgentEndpointsContext,
|
|
61
55
|
| "adminforth"
|
|
62
56
|
| "options"
|
|
63
|
-
| "getChatSurfaceConnectActionAdapters"
|
|
64
|
-
| "createChatSurfaceLinkToken"
|
|
65
57
|
| "handleChatSurfaceMessage"
|
|
66
58
|
>;
|
package/index.ts
CHANGED
|
@@ -28,7 +28,6 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
28
28
|
private sessionStore: AgentSessionStore;
|
|
29
29
|
private agentTurnService: AgentTurnService;
|
|
30
30
|
private chatSurfaceService: ChatSurfaceService;
|
|
31
|
-
private chatSurfaceSettingsPageRegistered = false;
|
|
32
31
|
private parseBody<T>(
|
|
33
32
|
schema: z.ZodType<T>,
|
|
34
33
|
body: unknown,
|
|
@@ -103,19 +102,6 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
103
102
|
hasAudioAdapter: Boolean(this.options.audioAdapter),
|
|
104
103
|
}
|
|
105
104
|
});
|
|
106
|
-
if (this.chatSurfaceService.getConnectActionAdapters().length && !this.chatSurfaceSettingsPageRegistered) {
|
|
107
|
-
if (!this.adminforth.config.auth!.userMenuSettingsPages) {
|
|
108
|
-
this.adminforth.config.auth!.userMenuSettingsPages = [];
|
|
109
|
-
}
|
|
110
|
-
this.adminforth.config.auth!.userMenuSettingsPages.push({
|
|
111
|
-
icon: "flowbite:link-outline",
|
|
112
|
-
pageLabel: "Chat Surfaces",
|
|
113
|
-
slug: "chat-surfaces",
|
|
114
|
-
component: this.componentPath("ChatSurfaceSettings.vue"),
|
|
115
|
-
isVisible: () => true,
|
|
116
|
-
});
|
|
117
|
-
this.chatSurfaceSettingsPageRegistered = true;
|
|
118
|
-
}
|
|
119
105
|
if (!this.adminforth.config.customization.customHeadItems) {
|
|
120
106
|
this.adminforth.config.customization.customHeadItems = [];
|
|
121
107
|
}
|
|
@@ -165,8 +151,6 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
165
151
|
getSessionTurns: this.sessionStore.getSessionTurns.bind(this.sessionStore),
|
|
166
152
|
createNewTurn: this.sessionStore.createNewTurn.bind(this.sessionStore),
|
|
167
153
|
createSystemTurn: this.sessionStore.createSystemTurn.bind(this.sessionStore),
|
|
168
|
-
getChatSurfaceConnectActionAdapters: this.chatSurfaceService.getConnectActionAdapters.bind(this.chatSurfaceService),
|
|
169
|
-
createChatSurfaceLinkToken: this.chatSurfaceService.createLinkToken.bind(this.chatSurfaceService),
|
|
170
154
|
handleChatSurfaceMessage: this.chatSurfaceService.handleMessage.bind(this.chatSurfaceService),
|
|
171
155
|
} satisfies AgentEndpointsContext;
|
|
172
156
|
|
package/package.json
CHANGED
package/types.ts
CHANGED
|
@@ -112,7 +112,16 @@ export interface PluginOptions extends PluginsCommonOptions {
|
|
|
112
112
|
checkpointResource?: ICheckpointResource;
|
|
113
113
|
|
|
114
114
|
/**
|
|
115
|
-
* Optional
|
|
115
|
+
* Optional resource configuration for resolving chat users through OAuth external identities.
|
|
116
116
|
*/
|
|
117
|
-
|
|
117
|
+
chatExternalIdentityResource?: {
|
|
118
|
+
resourceId: string;
|
|
119
|
+
adminUserIdField?: string;
|
|
120
|
+
providerField?: string;
|
|
121
|
+
subjectField?: string;
|
|
122
|
+
externalUserIdField?: string;
|
|
123
|
+
surfaces: Record<string, {
|
|
124
|
+
provider: string;
|
|
125
|
+
}>;
|
|
126
|
+
};
|
|
118
127
|
}
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="flex flex-col justify-center mr-6 md:mr-12">
|
|
3
|
-
<h2 class="flex items-start justify-start leading-none text-gray-800 dark:text-gray-50 text-3xl font-semibold">
|
|
4
|
-
{{ $t('Chat Surfaces') }}
|
|
5
|
-
</h2>
|
|
6
|
-
<p class="text-sm mt-3">
|
|
7
|
-
{{ $t('Connect external chat accounts to your AdminForth user') }}
|
|
8
|
-
</p>
|
|
9
|
-
|
|
10
|
-
<div class="mt-6 flex flex-wrap gap-4">
|
|
11
|
-
<div
|
|
12
|
-
v-for="surface in surfaces"
|
|
13
|
-
:key="surface.name"
|
|
14
|
-
class="flex flex-col w-full lg:w-72 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl p-4 shadow-sm"
|
|
15
|
-
>
|
|
16
|
-
<div class="flex items-center justify-between gap-3 mb-4">
|
|
17
|
-
<div class="min-w-0">
|
|
18
|
-
<p class="font-semibold text-gray-900 dark:text-white truncate">
|
|
19
|
-
{{ formatSurfaceName(surface.name) }}
|
|
20
|
-
</p>
|
|
21
|
-
<p class="text-xs text-gray-500 dark:text-gray-400">
|
|
22
|
-
{{ surface.externalUserId || $t('Not connected') }}
|
|
23
|
-
</p>
|
|
24
|
-
</div>
|
|
25
|
-
<span
|
|
26
|
-
class="shrink-0 inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium"
|
|
27
|
-
:class="surface.externalUserId
|
|
28
|
-
? 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200'
|
|
29
|
-
: 'bg-gray-100 text-gray-700 dark:bg-gray-700 dark:text-gray-300'"
|
|
30
|
-
>
|
|
31
|
-
{{ surface.externalUserId ? $t('Active') : $t('Inactive') }}
|
|
32
|
-
</span>
|
|
33
|
-
</div>
|
|
34
|
-
|
|
35
|
-
<div class="grid gap-2 mt-auto" :class="surface.externalUserId ? 'grid-cols-2' : 'grid-cols-1'">
|
|
36
|
-
<Button
|
|
37
|
-
class="w-full"
|
|
38
|
-
:disabled="isSurfaceBusy(surface.name)"
|
|
39
|
-
:loader="connectingSurfaceName === surface.name"
|
|
40
|
-
@click="connectSurface(surface.name)"
|
|
41
|
-
>
|
|
42
|
-
{{ surface.externalUserId ? $t('Reconnect') : $t('Connect') }}
|
|
43
|
-
</Button>
|
|
44
|
-
<Button
|
|
45
|
-
v-if="surface.externalUserId"
|
|
46
|
-
class="w-full"
|
|
47
|
-
:disabled="isSurfaceBusy(surface.name)"
|
|
48
|
-
:loader="disconnectingSurfaceName === surface.name"
|
|
49
|
-
@click="disconnectSurface(surface.name)"
|
|
50
|
-
>
|
|
51
|
-
{{ $t('Disconnect') }}
|
|
52
|
-
</Button>
|
|
53
|
-
</div>
|
|
54
|
-
</div>
|
|
55
|
-
</div>
|
|
56
|
-
</div>
|
|
57
|
-
</template>
|
|
58
|
-
|
|
59
|
-
<script setup lang="ts">
|
|
60
|
-
import { onMounted, ref } from 'vue';
|
|
61
|
-
import { Button } from '@/afcl';
|
|
62
|
-
import { callAdminForthApi } from '@/utils';
|
|
63
|
-
|
|
64
|
-
type ChatSurface = {
|
|
65
|
-
name: string;
|
|
66
|
-
externalUserId: string | null;
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
const surfaces = ref<ChatSurface[]>([]);
|
|
70
|
-
const connectingSurfaceName = ref<string | null>(null);
|
|
71
|
-
const disconnectingSurfaceName = ref<string | null>(null);
|
|
72
|
-
|
|
73
|
-
onMounted(loadSurfaces);
|
|
74
|
-
|
|
75
|
-
async function loadSurfaces() {
|
|
76
|
-
const response = await callAdminForthApi({
|
|
77
|
-
method: 'POST',
|
|
78
|
-
path: '/agent/surfaces/connectable',
|
|
79
|
-
body: {},
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
surfaces.value = response.surfaces;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
async function connectSurface(surfaceName: string) {
|
|
86
|
-
connectingSurfaceName.value = surfaceName;
|
|
87
|
-
|
|
88
|
-
try {
|
|
89
|
-
const response = await callAdminForthApi({
|
|
90
|
-
method: 'POST',
|
|
91
|
-
path: `/agent/surface/${surfaceName}/connect-action`,
|
|
92
|
-
body: {},
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
if (response.action.type === 'url') {
|
|
96
|
-
window.open(response.action.url, '_blank', 'noopener,noreferrer');
|
|
97
|
-
}
|
|
98
|
-
} finally {
|
|
99
|
-
connectingSurfaceName.value = null;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
async function disconnectSurface(surfaceName: string) {
|
|
104
|
-
disconnectingSurfaceName.value = surfaceName;
|
|
105
|
-
|
|
106
|
-
try {
|
|
107
|
-
await callAdminForthApi({
|
|
108
|
-
method: 'POST',
|
|
109
|
-
path: `/agent/surface/${surfaceName}/disconnect`,
|
|
110
|
-
body: {},
|
|
111
|
-
});
|
|
112
|
-
await loadSurfaces();
|
|
113
|
-
} finally {
|
|
114
|
-
disconnectingSurfaceName.value = null;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function isSurfaceBusy(surfaceName: string) {
|
|
119
|
-
return connectingSurfaceName.value === surfaceName || disconnectingSurfaceName.value === surfaceName;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function formatSurfaceName(surfaceName: string) {
|
|
123
|
-
return surfaceName.charAt(0).toUpperCase() + surfaceName.slice(1);
|
|
124
|
-
}
|
|
125
|
-
</script>
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="flex flex-col justify-center mr-6 md:mr-12">
|
|
3
|
-
<h2 class="flex items-start justify-start leading-none text-gray-800 dark:text-gray-50 text-3xl font-semibold">
|
|
4
|
-
{{ $t('Chat Surfaces') }}
|
|
5
|
-
</h2>
|
|
6
|
-
<p class="text-sm mt-3">
|
|
7
|
-
{{ $t('Connect external chat accounts to your AdminForth user') }}
|
|
8
|
-
</p>
|
|
9
|
-
|
|
10
|
-
<div class="mt-6 flex flex-wrap gap-4">
|
|
11
|
-
<div
|
|
12
|
-
v-for="surface in surfaces"
|
|
13
|
-
:key="surface.name"
|
|
14
|
-
class="flex flex-col w-full lg:w-72 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl p-4 shadow-sm"
|
|
15
|
-
>
|
|
16
|
-
<div class="flex items-center justify-between gap-3 mb-4">
|
|
17
|
-
<div class="min-w-0">
|
|
18
|
-
<p class="font-semibold text-gray-900 dark:text-white truncate">
|
|
19
|
-
{{ formatSurfaceName(surface.name) }}
|
|
20
|
-
</p>
|
|
21
|
-
<p class="text-xs text-gray-500 dark:text-gray-400">
|
|
22
|
-
{{ surface.externalUserId || $t('Not connected') }}
|
|
23
|
-
</p>
|
|
24
|
-
</div>
|
|
25
|
-
<span
|
|
26
|
-
class="shrink-0 inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium"
|
|
27
|
-
:class="surface.externalUserId
|
|
28
|
-
? 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200'
|
|
29
|
-
: 'bg-gray-100 text-gray-700 dark:bg-gray-700 dark:text-gray-300'"
|
|
30
|
-
>
|
|
31
|
-
{{ surface.externalUserId ? $t('Active') : $t('Inactive') }}
|
|
32
|
-
</span>
|
|
33
|
-
</div>
|
|
34
|
-
|
|
35
|
-
<div class="grid gap-2 mt-auto" :class="surface.externalUserId ? 'grid-cols-2' : 'grid-cols-1'">
|
|
36
|
-
<Button
|
|
37
|
-
class="w-full"
|
|
38
|
-
:disabled="isSurfaceBusy(surface.name)"
|
|
39
|
-
:loader="connectingSurfaceName === surface.name"
|
|
40
|
-
@click="connectSurface(surface.name)"
|
|
41
|
-
>
|
|
42
|
-
{{ surface.externalUserId ? $t('Reconnect') : $t('Connect') }}
|
|
43
|
-
</Button>
|
|
44
|
-
<Button
|
|
45
|
-
v-if="surface.externalUserId"
|
|
46
|
-
class="w-full"
|
|
47
|
-
:disabled="isSurfaceBusy(surface.name)"
|
|
48
|
-
:loader="disconnectingSurfaceName === surface.name"
|
|
49
|
-
@click="disconnectSurface(surface.name)"
|
|
50
|
-
>
|
|
51
|
-
{{ $t('Disconnect') }}
|
|
52
|
-
</Button>
|
|
53
|
-
</div>
|
|
54
|
-
</div>
|
|
55
|
-
</div>
|
|
56
|
-
</div>
|
|
57
|
-
</template>
|
|
58
|
-
|
|
59
|
-
<script setup lang="ts">
|
|
60
|
-
import { onMounted, ref } from 'vue';
|
|
61
|
-
import { Button } from '@/afcl';
|
|
62
|
-
import { callAdminForthApi } from '@/utils';
|
|
63
|
-
|
|
64
|
-
type ChatSurface = {
|
|
65
|
-
name: string;
|
|
66
|
-
externalUserId: string | null;
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
const surfaces = ref<ChatSurface[]>([]);
|
|
70
|
-
const connectingSurfaceName = ref<string | null>(null);
|
|
71
|
-
const disconnectingSurfaceName = ref<string | null>(null);
|
|
72
|
-
|
|
73
|
-
onMounted(loadSurfaces);
|
|
74
|
-
|
|
75
|
-
async function loadSurfaces() {
|
|
76
|
-
const response = await callAdminForthApi({
|
|
77
|
-
method: 'POST',
|
|
78
|
-
path: '/agent/surfaces/connectable',
|
|
79
|
-
body: {},
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
surfaces.value = response.surfaces;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
async function connectSurface(surfaceName: string) {
|
|
86
|
-
connectingSurfaceName.value = surfaceName;
|
|
87
|
-
|
|
88
|
-
try {
|
|
89
|
-
const response = await callAdminForthApi({
|
|
90
|
-
method: 'POST',
|
|
91
|
-
path: `/agent/surface/${surfaceName}/connect-action`,
|
|
92
|
-
body: {},
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
if (response.action.type === 'url') {
|
|
96
|
-
window.open(response.action.url, '_blank', 'noopener,noreferrer');
|
|
97
|
-
}
|
|
98
|
-
} finally {
|
|
99
|
-
connectingSurfaceName.value = null;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
async function disconnectSurface(surfaceName: string) {
|
|
104
|
-
disconnectingSurfaceName.value = surfaceName;
|
|
105
|
-
|
|
106
|
-
try {
|
|
107
|
-
await callAdminForthApi({
|
|
108
|
-
method: 'POST',
|
|
109
|
-
path: `/agent/surface/${surfaceName}/disconnect`,
|
|
110
|
-
body: {},
|
|
111
|
-
});
|
|
112
|
-
await loadSurfaces();
|
|
113
|
-
} finally {
|
|
114
|
-
disconnectingSurfaceName.value = null;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function isSurfaceBusy(surfaceName: string) {
|
|
119
|
-
return connectingSurfaceName.value === surfaceName || disconnectingSurfaceName.value === surfaceName;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function formatSurfaceName(surfaceName: string) {
|
|
123
|
-
return surfaceName.charAt(0).toUpperCase() + surfaceName.slice(1);
|
|
124
|
-
}
|
|
125
|
-
</script>
|