@adminforth/agent 1.45.1 → 1.47.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/build.log +2 -3
- package/chatSurfaceService.ts +215 -92
- package/dist/chatSurfaceService.d.ts +8 -19
- package/dist/chatSurfaceService.js +160 -64
- package/dist/endpoints/context.d.ts +2 -6
- package/dist/index.d.ts +0 -1
- package/dist/index.js +1 -19
- package/dist/types.d.ts +11 -2
- package/endpoints/context.ts +0 -8
- package/index.ts +1 -18
- package/package.json +1 -1
- package/types.ts +11 -2
- package/custom/ChatSurfaceSettings.vue +0 -125
- package/dist/custom/ChatSurfaceSettings.vue +0 -125
- package/dist/endpoints/chatSurfaces.d.ts +0 -3
- package/dist/endpoints/chatSurfaces.js +0 -91
- package/endpoints/chatSurfaces.ts +0 -93
|
@@ -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
|
@@ -13,7 +13,6 @@ import { AdminForthCheckpointSaver } from "./agent/checkpointer.js";
|
|
|
13
13
|
import { appendCustomSystemPrompt, buildAgentSystemPrompt, DEFAULT_AGENT_SYSTEM_PROMPT } from "./agent/systemPrompt.js";
|
|
14
14
|
import { setupCoreEndpoints } from "./endpoints/core.js";
|
|
15
15
|
import { setupSessionEndpoints } from "./endpoints/sessions.js";
|
|
16
|
-
import { setupChatSurfaceEndpoints } from "./endpoints/chatSurfaces.js";
|
|
17
16
|
import { AgentSessionStore } from "./sessionStore.js";
|
|
18
17
|
import { ChatSurfaceService } from "./chatSurfaceService.js";
|
|
19
18
|
import { AgentTurnService } from "./agentTurnService.js";
|
|
@@ -45,7 +44,6 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
45
44
|
constructor(options) {
|
|
46
45
|
super(options, import.meta.url);
|
|
47
46
|
this.checkpointer = null;
|
|
48
|
-
this.chatSurfaceSettingsPageRegistered = false;
|
|
49
47
|
this.options = options;
|
|
50
48
|
this.sessionStore = new AgentSessionStore(() => this.adminforth, this.options);
|
|
51
49
|
this.agentTurnService = new AgentTurnService({
|
|
@@ -57,7 +55,7 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
57
55
|
getInternalAgentResourceIds: this.getInternalAgentResourceIds.bind(this),
|
|
58
56
|
getAgentSystemPrompt: () => this.agentSystemPromptPromise,
|
|
59
57
|
});
|
|
60
|
-
this.chatSurfaceService = new ChatSurfaceService(() => this.adminforth, this.options, this.sessionStore, this.agentTurnService.handleTurn.bind(this.agentTurnService));
|
|
58
|
+
this.chatSurfaceService = new ChatSurfaceService(() => this.adminforth, this.options, this.sessionStore, this.agentTurnService.handleTurn.bind(this.agentTurnService), this.agentTurnService.runAndPersistAgentResponse.bind(this.agentTurnService));
|
|
61
59
|
this.agentSystemPromptPromise = Promise.resolve(appendCustomSystemPrompt(DEFAULT_AGENT_SYSTEM_PROMPT, this.options.systemPrompt));
|
|
62
60
|
this.shouldHaveSingleInstancePerWholeApp = () => false;
|
|
63
61
|
}
|
|
@@ -84,19 +82,6 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
84
82
|
hasAudioAdapter: Boolean(this.options.audioAdapter),
|
|
85
83
|
}
|
|
86
84
|
});
|
|
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
85
|
if (!this.adminforth.config.customization.customHeadItems) {
|
|
101
86
|
this.adminforth.config.customization.customHeadItems = [];
|
|
102
87
|
}
|
|
@@ -139,12 +124,9 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
139
124
|
getSessionTurns: this.sessionStore.getSessionTurns.bind(this.sessionStore),
|
|
140
125
|
createNewTurn: this.sessionStore.createNewTurn.bind(this.sessionStore),
|
|
141
126
|
createSystemTurn: this.sessionStore.createSystemTurn.bind(this.sessionStore),
|
|
142
|
-
getChatSurfaceConnectActionAdapters: this.chatSurfaceService.getConnectActionAdapters.bind(this.chatSurfaceService),
|
|
143
|
-
createChatSurfaceLinkToken: this.chatSurfaceService.createLinkToken.bind(this.chatSurfaceService),
|
|
144
127
|
handleChatSurfaceMessage: this.chatSurfaceService.handleMessage.bind(this.chatSurfaceService),
|
|
145
128
|
};
|
|
146
129
|
setupCoreEndpoints(endpointContext, server);
|
|
147
130
|
setupSessionEndpoints(endpointContext, server);
|
|
148
|
-
setupChatSurfaceEndpoints(endpointContext, server);
|
|
149
131
|
}
|
|
150
132
|
}
|
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 {};
|
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
|
@@ -13,7 +13,6 @@ import { AdminForthCheckpointSaver } from "./agent/checkpointer.js";
|
|
|
13
13
|
import { appendCustomSystemPrompt, buildAgentSystemPrompt, DEFAULT_AGENT_SYSTEM_PROMPT} from "./agent/systemPrompt.js";
|
|
14
14
|
import { setupCoreEndpoints } from "./endpoints/core.js";
|
|
15
15
|
import { setupSessionEndpoints } from "./endpoints/sessions.js";
|
|
16
|
-
import { setupChatSurfaceEndpoints } from "./endpoints/chatSurfaces.js";
|
|
17
16
|
import type { AgentEndpointsContext } from "./endpoints/context.js";
|
|
18
17
|
import { AgentSessionStore } from "./sessionStore.js";
|
|
19
18
|
import { ChatSurfaceService } from "./chatSurfaceService.js";
|
|
@@ -28,7 +27,6 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
28
27
|
private sessionStore: AgentSessionStore;
|
|
29
28
|
private agentTurnService: AgentTurnService;
|
|
30
29
|
private chatSurfaceService: ChatSurfaceService;
|
|
31
|
-
private chatSurfaceSettingsPageRegistered = false;
|
|
32
30
|
private parseBody<T>(
|
|
33
31
|
schema: z.ZodType<T>,
|
|
34
32
|
body: unknown,
|
|
@@ -77,6 +75,7 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
77
75
|
this.options,
|
|
78
76
|
this.sessionStore,
|
|
79
77
|
this.agentTurnService.handleTurn.bind(this.agentTurnService),
|
|
78
|
+
this.agentTurnService.runAndPersistAgentResponse.bind(this.agentTurnService),
|
|
80
79
|
);
|
|
81
80
|
this.agentSystemPromptPromise = Promise.resolve(
|
|
82
81
|
appendCustomSystemPrompt(DEFAULT_AGENT_SYSTEM_PROMPT, this.options.systemPrompt),
|
|
@@ -102,19 +101,6 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
102
101
|
hasAudioAdapter: Boolean(this.options.audioAdapter),
|
|
103
102
|
}
|
|
104
103
|
});
|
|
105
|
-
if (this.chatSurfaceService.getConnectActionAdapters().length && !this.chatSurfaceSettingsPageRegistered) {
|
|
106
|
-
if (!this.adminforth.config.auth!.userMenuSettingsPages) {
|
|
107
|
-
this.adminforth.config.auth!.userMenuSettingsPages = [];
|
|
108
|
-
}
|
|
109
|
-
this.adminforth.config.auth!.userMenuSettingsPages.push({
|
|
110
|
-
icon: "flowbite:link-outline",
|
|
111
|
-
pageLabel: "Chat Surfaces",
|
|
112
|
-
slug: "chat-surfaces",
|
|
113
|
-
component: this.componentPath("ChatSurfaceSettings.vue"),
|
|
114
|
-
isVisible: () => true,
|
|
115
|
-
});
|
|
116
|
-
this.chatSurfaceSettingsPageRegistered = true;
|
|
117
|
-
}
|
|
118
104
|
if (!this.adminforth.config.customization.customHeadItems) {
|
|
119
105
|
this.adminforth.config.customization.customHeadItems = [];
|
|
120
106
|
}
|
|
@@ -164,13 +150,10 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
164
150
|
getSessionTurns: this.sessionStore.getSessionTurns.bind(this.sessionStore),
|
|
165
151
|
createNewTurn: this.sessionStore.createNewTurn.bind(this.sessionStore),
|
|
166
152
|
createSystemTurn: this.sessionStore.createSystemTurn.bind(this.sessionStore),
|
|
167
|
-
getChatSurfaceConnectActionAdapters: this.chatSurfaceService.getConnectActionAdapters.bind(this.chatSurfaceService),
|
|
168
|
-
createChatSurfaceLinkToken: this.chatSurfaceService.createLinkToken.bind(this.chatSurfaceService),
|
|
169
153
|
handleChatSurfaceMessage: this.chatSurfaceService.handleMessage.bind(this.chatSurfaceService),
|
|
170
154
|
} satisfies AgentEndpointsContext;
|
|
171
155
|
|
|
172
156
|
setupCoreEndpoints(endpointContext, server);
|
|
173
157
|
setupSessionEndpoints(endpointContext, server);
|
|
174
|
-
setupChatSurfaceEndpoints(endpointContext, server);
|
|
175
158
|
}
|
|
176
159
|
}
|
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>
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
const DEFAULT_ADMIN_USER_EXTERNAL_USER_ID_FIELD = "externalUserId";
|
|
11
|
-
export function setupChatSurfaceEndpoints(ctx, server) {
|
|
12
|
-
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
|
-
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
|
-
server.endpoint({
|
|
65
|
-
method: "POST",
|
|
66
|
-
noAuth: true,
|
|
67
|
-
path: `/agent/surface/${adapter.name}/webhook`,
|
|
68
|
-
handler: (endpointInput) => __awaiter(this, void 0, void 0, function* () {
|
|
69
|
-
var _a;
|
|
70
|
-
const surfaceContext = {
|
|
71
|
-
body: endpointInput.body,
|
|
72
|
-
headers: endpointInput.headers,
|
|
73
|
-
abortSignal: endpointInput.abortSignal,
|
|
74
|
-
rawRequest: endpointInput._raw_express_req,
|
|
75
|
-
rawResponse: endpointInput._raw_express_res,
|
|
76
|
-
};
|
|
77
|
-
const incoming = yield adapter.parseIncomingMessage(surfaceContext);
|
|
78
|
-
if (!incoming)
|
|
79
|
-
return { ok: true };
|
|
80
|
-
const sink = yield adapter.createEventSink(surfaceContext, incoming);
|
|
81
|
-
try {
|
|
82
|
-
yield ctx.handleChatSurfaceMessage(adapter, incoming, sink);
|
|
83
|
-
}
|
|
84
|
-
finally {
|
|
85
|
-
yield ((_a = sink.close) === null || _a === void 0 ? void 0 : _a.call(sink));
|
|
86
|
-
}
|
|
87
|
-
return { ok: true };
|
|
88
|
-
}),
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
IAdminForthEndpointHandlerInput,
|
|
3
|
-
IHttpServer,
|
|
4
|
-
} from "adminforth";
|
|
5
|
-
import type { ChatSurfaceAdapterWithConnectAction, ChatSurfaceEndpointsContext } from "./context.js";
|
|
6
|
-
|
|
7
|
-
const DEFAULT_ADMIN_USER_EXTERNAL_USER_ID_FIELD = "externalUserId";
|
|
8
|
-
|
|
9
|
-
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
|
-
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
|
-
server.endpoint({
|
|
66
|
-
method: "POST",
|
|
67
|
-
noAuth: true,
|
|
68
|
-
path: `/agent/surface/${adapter.name}/webhook`,
|
|
69
|
-
handler: async (endpointInput: IAdminForthEndpointHandlerInput) => {
|
|
70
|
-
const surfaceContext = {
|
|
71
|
-
body: endpointInput.body,
|
|
72
|
-
headers: endpointInput.headers,
|
|
73
|
-
abortSignal: endpointInput.abortSignal,
|
|
74
|
-
rawRequest: endpointInput._raw_express_req,
|
|
75
|
-
rawResponse: endpointInput._raw_express_res,
|
|
76
|
-
};
|
|
77
|
-
const incoming = await adapter.parseIncomingMessage(surfaceContext);
|
|
78
|
-
|
|
79
|
-
if (!incoming) return { ok: true };
|
|
80
|
-
|
|
81
|
-
const sink = await adapter.createEventSink(surfaceContext, incoming);
|
|
82
|
-
|
|
83
|
-
try {
|
|
84
|
-
await ctx.handleChatSurfaceMessage(adapter, incoming, sink);
|
|
85
|
-
} finally {
|
|
86
|
-
await sink.close?.();
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return { ok: true };
|
|
90
|
-
},
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
}
|