@adminforth/agent 1.45.1 → 1.46.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 CHANGED
@@ -63,5 +63,5 @@ custom/speech_recognition_frontend/voiceActivityDetection.ts
63
63
  custom/speech_recognition_frontend/types/
64
64
  custom/speech_recognition_frontend/types/voice-activity-detection.d.ts
65
65
 
66
- sent 1,671,664 bytes received 936 bytes 3,345,200.00 bytes/sec
66
+ sent 1,671,668 bytes received 940 bytes 3,345,216.00 bytes/sec
67
67
  total size is 1,667,436 speedup is 1.00
@@ -5,12 +5,18 @@ import type {
5
5
  ChatSurfaceIncomingMessage,
6
6
  IAdminForth,
7
7
  } from "adminforth";
8
- import { Filters } from "adminforth";
8
+ import { Filters, logger } from "adminforth";
9
9
  import { randomUUID } from "crypto";
10
10
  import type { AgentEventEmitter } from "./agentEvents.js";
11
- import type { HandleTurnInput } from "./agentTurnService.js";
11
+ import type {
12
+ HandleTurnInput,
13
+ RunAndPersistAgentResponseInput,
14
+ RunAndPersistAgentResponseResult,
15
+ } from "./agentTurnService.js";
12
16
  import type { PluginOptions } from "./types.js";
13
17
  import type { AgentSessionStore } from "./sessionStore.js";
18
+ import { getErrorMessage, isAbortError } from "./errors.js";
19
+ import { sanitizeSpeechText } from "./sanitizeSpeechText.js";
14
20
 
15
21
  type ChatSurfaceConnectAction = {
16
22
  type: "url";
@@ -18,6 +24,23 @@ type ChatSurfaceConnectAction = {
18
24
  url: string;
19
25
  };
20
26
 
27
+ type ChatSurfaceIncomingMessageWithAudio = ChatSurfaceIncomingMessage & {
28
+ audio?: {
29
+ buffer: Buffer;
30
+ filename: string;
31
+ mimeType: string;
32
+ };
33
+ };
34
+
35
+ type ChatSurfaceEventSinkWithAudio = ChatSurfaceEventSink & {
36
+ emit(event: Parameters<ChatSurfaceEventSink["emit"]>[0] | {
37
+ type: "audio";
38
+ audio: Buffer;
39
+ filename: string;
40
+ mimeType: string;
41
+ }): void | Promise<void>;
42
+ };
43
+
21
44
  export type ChatSurfaceAdapterWithConnectAction = ChatSurfaceAdapter & {
22
45
  createConnectAction?(input: {
23
46
  token: string;
@@ -41,6 +64,9 @@ export class ChatSurfaceService {
41
64
  private options: PluginOptions,
42
65
  private sessionStore: AgentSessionStore,
43
66
  private handleTurn: (input: HandleTurnInput) => Promise<unknown>,
67
+ private runAndPersistAgentResponse: (
68
+ input: RunAndPersistAgentResponseInput,
69
+ ) => Promise<RunAndPersistAgentResponseResult>,
44
70
  ) {}
45
71
 
46
72
  getConnectActionAdapters() {
@@ -108,10 +134,35 @@ export class ChatSurfaceService {
108
134
  incoming: ChatSurfaceIncomingMessage,
109
135
  sink: ChatSurfaceEventSink,
110
136
  ) {
111
- if (typeof incoming.metadata?.startPayload !== "string") {
137
+ if (incoming.metadata?.isStartCommand !== true) {
112
138
  return false;
113
139
  }
114
140
 
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
+
115
166
  const payload = this.consumeLinkToken(incoming.surface, incoming.metadata.startPayload);
116
167
  if (!payload) {
117
168
  await sink.emit({
@@ -120,11 +171,7 @@ export class ChatSurfaceService {
120
171
  });
121
172
  return true;
122
173
  }
123
- const externalUserIdField = this.options.chatExternalIdsField ?? DEFAULT_ADMIN_USER_EXTERNAL_USER_ID_FIELD;
124
- const adminforth = this.getAdminforth();
125
- const authResourceId = adminforth.config.auth!.usersResourceId!;
126
- const authResource = adminforth.config.resources.find((resource) => resource.resourceId === authResourceId)!;
127
- const primaryKeyField = authResource.columns.find((column) => column.primaryKey)!.name!;
174
+
128
175
  const adminUserRecord = await adminforth.resource(authResourceId).get([
129
176
  Filters.EQ(primaryKeyField, payload.adminUserId),
130
177
  ]);
@@ -143,6 +190,143 @@ export class ChatSurfaceService {
143
190
  return true;
144
191
  }
145
192
 
193
+ private async handleAudioMessage(
194
+ incoming: ChatSurfaceIncomingMessageWithAudio,
195
+ sink: ChatSurfaceEventSinkWithAudio,
196
+ adminUser: AdminUser,
197
+ ) {
198
+ const audioAdapter = this.options.audioAdapter;
199
+ if (!audioAdapter) {
200
+ await sink.emit({
201
+ type: "error",
202
+ message: "Audio adapter is not configured for AdminForth Agent.",
203
+ });
204
+ return;
205
+ }
206
+
207
+ let transcription;
208
+
209
+ try {
210
+ transcription = await audioAdapter.transcribe({
211
+ buffer: incoming.audio!.buffer,
212
+ filename: incoming.audio!.filename,
213
+ mimeType: incoming.audio!.mimeType,
214
+ language: "auto",
215
+ });
216
+ } catch (error) {
217
+ if (isAbortError(error)) {
218
+ logger.info(`Agent ${incoming.surface} surface speech transcription aborted`);
219
+ return;
220
+ }
221
+
222
+ logger.error(`Agent ${incoming.surface} surface speech transcription failed:\n${getErrorMessage(error)}`);
223
+ await sink.emit({
224
+ type: "error",
225
+ message: "Speech transcription failed. Check server logs for details.",
226
+ });
227
+ return;
228
+ }
229
+
230
+ if (!transcription.text) {
231
+ await sink.emit({
232
+ type: "error",
233
+ message: "Speech transcription is empty",
234
+ });
235
+ return;
236
+ }
237
+
238
+ const agentResponse = await this.handleAgentSurfaceResponse(
239
+ incoming,
240
+ sink,
241
+ adminUser,
242
+ transcription.text,
243
+ { emitDone: false },
244
+ );
245
+
246
+ if (!agentResponse || agentResponse.aborted || agentResponse.failed) {
247
+ return;
248
+ }
249
+
250
+ await sink.emit({
251
+ type: "done",
252
+ text: agentResponse.text,
253
+ });
254
+
255
+ try {
256
+ const speech = await audioAdapter.synthesize({
257
+ text: sanitizeSpeechText(agentResponse.text),
258
+ stream: false,
259
+ format: "opus",
260
+ });
261
+
262
+ await sink.emit({
263
+ type: "audio",
264
+ audio: speech.audio,
265
+ filename: "agent-response.ogg",
266
+ mimeType: speech.mimeType,
267
+ });
268
+ } catch (error) {
269
+ if (isAbortError(error)) {
270
+ logger.info(`Agent ${incoming.surface} surface speech synthesis aborted`);
271
+ return;
272
+ }
273
+
274
+ logger.error(`Agent ${incoming.surface} surface speech synthesis failed:\n${getErrorMessage(error)}`);
275
+ await sink.emit({
276
+ type: "error",
277
+ message: getErrorMessage(error),
278
+ });
279
+ }
280
+ }
281
+
282
+ private async handleAgentSurfaceResponse(
283
+ incoming: ChatSurfaceIncomingMessage,
284
+ sink: ChatSurfaceEventSink,
285
+ adminUser: AdminUser,
286
+ prompt: string,
287
+ options?: { emitDone?: boolean },
288
+ ) {
289
+ const emitDone = options?.emitDone ?? true;
290
+ const sessionId = await this.sessionStore.getOrCreateChatSurfaceSession(
291
+ { ...incoming, prompt },
292
+ adminUser,
293
+ );
294
+
295
+ if (emitDone) {
296
+ await this.handleTurn({
297
+ prompt,
298
+ sessionId,
299
+ modeName: incoming.modeName,
300
+ userTimeZone: incoming.userTimeZone ?? "UTC",
301
+ adminUser,
302
+ emit: this.createEventEmitter(sink),
303
+ failureLogMessage: `Agent ${incoming.surface} surface response failed`,
304
+ abortLogMessage: `Agent ${incoming.surface} surface response aborted`,
305
+ });
306
+ return null;
307
+ }
308
+
309
+ const agentResponse = await this.runAndPersistAgentResponse({
310
+ prompt,
311
+ sessionId,
312
+ modeName: incoming.modeName,
313
+ userTimeZone: incoming.userTimeZone ?? "UTC",
314
+ adminUser,
315
+ emit: this.createEventEmitter(sink),
316
+ failureLogMessage: `Agent ${incoming.surface} surface response failed`,
317
+ abortLogMessage: `Agent ${incoming.surface} surface response aborted`,
318
+ });
319
+
320
+ if (agentResponse.failed) {
321
+ await sink.emit({
322
+ type: "error",
323
+ message: agentResponse.text,
324
+ });
325
+ }
326
+
327
+ return agentResponse;
328
+ }
329
+
146
330
  async handleMessage(
147
331
  adapter: ChatSurfaceAdapter,
148
332
  incoming: ChatSurfaceIncomingMessage,
@@ -175,15 +359,12 @@ export class ChatSurfaceService {
175
359
  dbUser: adminUserRecord,
176
360
  };
177
361
 
178
- await this.handleTurn({
179
- prompt: incoming.prompt,
180
- sessionId: await this.sessionStore.getOrCreateChatSurfaceSession(incoming, adminUser),
181
- modeName: incoming.modeName,
182
- userTimeZone: incoming.userTimeZone ?? "UTC",
183
- adminUser,
184
- emit: this.createEventEmitter(sink),
185
- failureLogMessage: `Agent ${incoming.surface} surface response failed`,
186
- abortLogMessage: `Agent ${incoming.surface} surface response aborted`,
187
- });
362
+ const incomingWithAudio = incoming as ChatSurfaceIncomingMessageWithAudio;
363
+ if (incomingWithAudio.audio) {
364
+ await this.handleAudioMessage(incomingWithAudio, sink as ChatSurfaceEventSinkWithAudio, adminUser);
365
+ return;
366
+ }
367
+
368
+ await this.handleAgentSurfaceResponse(incoming, sink, adminUser, incoming.prompt);
188
369
  }
189
370
  }
@@ -1,5 +1,5 @@
1
1
  import type { AdminUser, ChatSurfaceAdapter, ChatSurfaceEventSink, ChatSurfaceIncomingMessage, IAdminForth } from "adminforth";
2
- import type { HandleTurnInput } from "./agentTurnService.js";
2
+ import type { HandleTurnInput, RunAndPersistAgentResponseInput, RunAndPersistAgentResponseResult } from "./agentTurnService.js";
3
3
  import type { PluginOptions } from "./types.js";
4
4
  import type { AgentSessionStore } from "./sessionStore.js";
5
5
  type ChatSurfaceConnectAction = {
@@ -17,13 +17,16 @@ export declare class ChatSurfaceService {
17
17
  private options;
18
18
  private sessionStore;
19
19
  private handleTurn;
20
+ private runAndPersistAgentResponse;
20
21
  private linkTokens;
21
- constructor(getAdminforth: () => IAdminForth, options: PluginOptions, sessionStore: AgentSessionStore, handleTurn: (input: HandleTurnInput) => Promise<unknown>);
22
+ constructor(getAdminforth: () => IAdminForth, options: PluginOptions, sessionStore: AgentSessionStore, handleTurn: (input: HandleTurnInput) => Promise<unknown>, runAndPersistAgentResponse: (input: RunAndPersistAgentResponseInput) => Promise<RunAndPersistAgentResponseResult>);
22
23
  getConnectActionAdapters(): ChatSurfaceAdapterWithConnectAction[];
23
24
  createLinkToken(surface: string, adminUser: AdminUser): `${string}-${string}-${string}-${string}-${string}`;
24
25
  private consumeLinkToken;
25
26
  private createEventEmitter;
26
27
  private handleLink;
28
+ private handleAudioMessage;
29
+ private handleAgentSurfaceResponse;
27
30
  handleMessage(adapter: ChatSurfaceAdapter, incoming: ChatSurfaceIncomingMessage, sink: ChatSurfaceEventSink): Promise<void>;
28
31
  }
29
32
  export {};
@@ -7,16 +7,19 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { Filters } from "adminforth";
10
+ import { Filters, logger } from "adminforth";
11
11
  import { randomUUID } from "crypto";
12
+ import { getErrorMessage, isAbortError } from "./errors.js";
13
+ import { sanitizeSpeechText } from "./sanitizeSpeechText.js";
12
14
  const DEFAULT_ADMIN_USER_EXTERNAL_USER_ID_FIELD = "externalUserId";
13
15
  const CHAT_SURFACE_LINK_TOKEN_TTL_MS = 60 * 1000;
14
16
  export class ChatSurfaceService {
15
- constructor(getAdminforth, options, sessionStore, handleTurn) {
17
+ constructor(getAdminforth, options, sessionStore, handleTurn, runAndPersistAgentResponse) {
16
18
  this.getAdminforth = getAdminforth;
17
19
  this.options = options;
18
20
  this.sessionStore = sessionStore;
19
21
  this.handleTurn = handleTurn;
22
+ this.runAndPersistAgentResponse = runAndPersistAgentResponse;
20
23
  this.linkTokens = new Map();
21
24
  }
22
25
  getConnectActionAdapters() {
@@ -73,10 +76,30 @@ export class ChatSurfaceService {
73
76
  }
74
77
  handleLink(incoming, sink) {
75
78
  return __awaiter(this, void 0, void 0, function* () {
76
- var _a, _b, _c;
77
- if (typeof ((_a = incoming.metadata) === null || _a === void 0 ? void 0 : _a.startPayload) !== "string") {
79
+ var _a, _b, _c, _d;
80
+ if (((_a = incoming.metadata) === null || _a === void 0 ? void 0 : _a.isStartCommand) !== true) {
78
81
  return false;
79
82
  }
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
+ }
80
103
  const payload = this.consumeLinkToken(incoming.surface, incoming.metadata.startPayload);
81
104
  if (!payload) {
82
105
  yield sink.emit({
@@ -85,16 +108,11 @@ export class ChatSurfaceService {
85
108
  });
86
109
  return true;
87
110
  }
88
- const externalUserIdField = (_b = this.options.chatExternalIdsField) !== null && _b !== void 0 ? _b : DEFAULT_ADMIN_USER_EXTERNAL_USER_ID_FIELD;
89
- const adminforth = this.getAdminforth();
90
- const authResourceId = adminforth.config.auth.usersResourceId;
91
- const authResource = adminforth.config.resources.find((resource) => resource.resourceId === authResourceId);
92
- const primaryKeyField = authResource.columns.find((column) => column.primaryKey).name;
93
111
  const adminUserRecord = yield adminforth.resource(authResourceId).get([
94
112
  Filters.EQ(primaryKeyField, payload.adminUserId),
95
113
  ]);
96
114
  yield adminforth.resource(authResourceId).update(payload.adminUserId, {
97
- [externalUserIdField]: Object.assign(Object.assign({}, ((_c = adminUserRecord[externalUserIdField]) !== null && _c !== void 0 ? _c : {})), { [incoming.surface]: incoming.externalUserId }),
115
+ [externalUserIdField]: Object.assign(Object.assign({}, ((_d = adminUserRecord[externalUserIdField]) !== null && _d !== void 0 ? _d : {})), { [incoming.surface]: incoming.externalUserId }),
98
116
  });
99
117
  yield sink.emit({
100
118
  type: "done",
@@ -103,9 +121,118 @@ export class ChatSurfaceService {
103
121
  return true;
104
122
  });
105
123
  }
124
+ handleAudioMessage(incoming, sink, adminUser) {
125
+ return __awaiter(this, void 0, void 0, function* () {
126
+ const audioAdapter = this.options.audioAdapter;
127
+ if (!audioAdapter) {
128
+ yield sink.emit({
129
+ type: "error",
130
+ message: "Audio adapter is not configured for AdminForth Agent.",
131
+ });
132
+ return;
133
+ }
134
+ let transcription;
135
+ try {
136
+ transcription = yield audioAdapter.transcribe({
137
+ buffer: incoming.audio.buffer,
138
+ filename: incoming.audio.filename,
139
+ mimeType: incoming.audio.mimeType,
140
+ language: "auto",
141
+ });
142
+ }
143
+ catch (error) {
144
+ if (isAbortError(error)) {
145
+ logger.info(`Agent ${incoming.surface} surface speech transcription aborted`);
146
+ return;
147
+ }
148
+ logger.error(`Agent ${incoming.surface} surface speech transcription failed:\n${getErrorMessage(error)}`);
149
+ yield sink.emit({
150
+ type: "error",
151
+ message: "Speech transcription failed. Check server logs for details.",
152
+ });
153
+ return;
154
+ }
155
+ if (!transcription.text) {
156
+ yield sink.emit({
157
+ type: "error",
158
+ message: "Speech transcription is empty",
159
+ });
160
+ return;
161
+ }
162
+ const agentResponse = yield this.handleAgentSurfaceResponse(incoming, sink, adminUser, transcription.text, { emitDone: false });
163
+ if (!agentResponse || agentResponse.aborted || agentResponse.failed) {
164
+ return;
165
+ }
166
+ yield sink.emit({
167
+ type: "done",
168
+ text: agentResponse.text,
169
+ });
170
+ try {
171
+ const speech = yield audioAdapter.synthesize({
172
+ text: sanitizeSpeechText(agentResponse.text),
173
+ stream: false,
174
+ format: "opus",
175
+ });
176
+ yield sink.emit({
177
+ type: "audio",
178
+ audio: speech.audio,
179
+ filename: "agent-response.ogg",
180
+ mimeType: speech.mimeType,
181
+ });
182
+ }
183
+ catch (error) {
184
+ if (isAbortError(error)) {
185
+ logger.info(`Agent ${incoming.surface} surface speech synthesis aborted`);
186
+ return;
187
+ }
188
+ logger.error(`Agent ${incoming.surface} surface speech synthesis failed:\n${getErrorMessage(error)}`);
189
+ yield sink.emit({
190
+ type: "error",
191
+ message: getErrorMessage(error),
192
+ });
193
+ }
194
+ });
195
+ }
196
+ handleAgentSurfaceResponse(incoming, sink, adminUser, prompt, options) {
197
+ return __awaiter(this, void 0, void 0, function* () {
198
+ var _a, _b, _c;
199
+ const emitDone = (_a = options === null || options === void 0 ? void 0 : options.emitDone) !== null && _a !== void 0 ? _a : true;
200
+ const sessionId = yield this.sessionStore.getOrCreateChatSurfaceSession(Object.assign(Object.assign({}, incoming), { prompt }), adminUser);
201
+ if (emitDone) {
202
+ yield this.handleTurn({
203
+ prompt,
204
+ sessionId,
205
+ modeName: incoming.modeName,
206
+ userTimeZone: (_b = incoming.userTimeZone) !== null && _b !== void 0 ? _b : "UTC",
207
+ adminUser,
208
+ emit: this.createEventEmitter(sink),
209
+ failureLogMessage: `Agent ${incoming.surface} surface response failed`,
210
+ abortLogMessage: `Agent ${incoming.surface} surface response aborted`,
211
+ });
212
+ return null;
213
+ }
214
+ const agentResponse = yield this.runAndPersistAgentResponse({
215
+ prompt,
216
+ sessionId,
217
+ modeName: incoming.modeName,
218
+ userTimeZone: (_c = incoming.userTimeZone) !== null && _c !== void 0 ? _c : "UTC",
219
+ adminUser,
220
+ emit: this.createEventEmitter(sink),
221
+ failureLogMessage: `Agent ${incoming.surface} surface response failed`,
222
+ abortLogMessage: `Agent ${incoming.surface} surface response aborted`,
223
+ });
224
+ if (agentResponse.failed) {
225
+ yield sink.emit({
226
+ type: "error",
227
+ message: agentResponse.text,
228
+ });
229
+ }
230
+ return agentResponse;
231
+ });
232
+ }
106
233
  handleMessage(adapter, incoming, sink) {
107
234
  return __awaiter(this, void 0, void 0, function* () {
108
- var _a, _b;
235
+ var _a;
109
236
  if (yield this.handleLink(incoming, sink)) {
110
237
  return;
111
238
  }
@@ -127,16 +254,12 @@ export class ChatSurfaceService {
127
254
  username: adminUserRecord[adminforth.config.auth.usernameField],
128
255
  dbUser: adminUserRecord,
129
256
  };
130
- yield this.handleTurn({
131
- prompt: incoming.prompt,
132
- sessionId: yield this.sessionStore.getOrCreateChatSurfaceSession(incoming, adminUser),
133
- modeName: incoming.modeName,
134
- userTimeZone: (_b = incoming.userTimeZone) !== null && _b !== void 0 ? _b : "UTC",
135
- adminUser,
136
- emit: this.createEventEmitter(sink),
137
- failureLogMessage: `Agent ${incoming.surface} surface response failed`,
138
- abortLogMessage: `Agent ${incoming.surface} surface response aborted`,
139
- });
257
+ const incomingWithAudio = incoming;
258
+ if (incomingWithAudio.audio) {
259
+ yield this.handleAudioMessage(incomingWithAudio, sink, adminUser);
260
+ return;
261
+ }
262
+ yield this.handleAgentSurfaceResponse(incoming, sink, adminUser, incoming.prompt);
140
263
  });
141
264
  }
142
265
  }
package/dist/index.js CHANGED
@@ -57,7 +57,7 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
57
57
  getInternalAgentResourceIds: this.getInternalAgentResourceIds.bind(this),
58
58
  getAgentSystemPrompt: () => this.agentSystemPromptPromise,
59
59
  });
60
- this.chatSurfaceService = new ChatSurfaceService(() => this.adminforth, this.options, this.sessionStore, this.agentTurnService.handleTurn.bind(this.agentTurnService));
60
+ this.chatSurfaceService = new ChatSurfaceService(() => this.adminforth, this.options, this.sessionStore, this.agentTurnService.handleTurn.bind(this.agentTurnService), this.agentTurnService.runAndPersistAgentResponse.bind(this.agentTurnService));
61
61
  this.agentSystemPromptPromise = Promise.resolve(appendCustomSystemPrompt(DEFAULT_AGENT_SYSTEM_PROMPT, this.options.systemPrompt));
62
62
  this.shouldHaveSingleInstancePerWholeApp = () => false;
63
63
  }
package/index.ts CHANGED
@@ -77,6 +77,7 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
77
77
  this.options,
78
78
  this.sessionStore,
79
79
  this.agentTurnService.handleTurn.bind(this.agentTurnService),
80
+ this.agentTurnService.runAndPersistAgentResponse.bind(this.agentTurnService),
80
81
  );
81
82
  this.agentSystemPromptPromise = Promise.resolve(
82
83
  appendCustomSystemPrompt(DEFAULT_AGENT_SYSTEM_PROMPT, this.options.systemPrompt),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/agent",
3
- "version": "1.45.1",
3
+ "version": "1.46.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",