@adminforth/agent 1.43.28 → 1.44.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/agent/checkpointer.ts +2 -1
- package/agent/systemPrompt.ts +2 -1
- package/agentEvents.ts +61 -0
- package/agentResponseEvents.ts +1 -206
- package/apiBasedTools.ts +7 -3
- package/dist/agent/checkpointer.d.ts +29 -0
- package/dist/agent/languageDetect.d.ts +10 -0
- package/dist/agent/middleware/apiBasedTools.d.ts +3 -0
- package/dist/agent/middleware/openAiResponsesContinuation.d.ts +1 -0
- package/dist/agent/middleware/sequenceDebug.d.ts +46 -0
- package/dist/agent/simpleAgent.d.ts +61 -0
- package/dist/agent/skills/registry.d.ts +13 -0
- package/dist/agent/systemPrompt.d.ts +11 -0
- package/dist/agent/systemPrompt.js +3 -1
- package/dist/agent/toolCallEvents.d.ts +27 -0
- package/dist/agent/tools/apiTool.d.ts +6 -0
- package/dist/agent/tools/fetchSkill.d.ts +8 -0
- package/dist/agent/tools/fetchToolSchema.d.ts +9 -0
- package/dist/agent/tools/getUserLocation.d.ts +8 -0
- package/dist/agent/tools/index.d.ts +4 -0
- package/dist/agentEvents.d.ts +52 -0
- package/dist/agentEvents.js +1 -0
- package/dist/agentResponseEvents.d.ts +1 -0
- package/dist/agentResponseEvents.js +1 -144
- package/dist/apiBasedTools.d.ts +29 -0
- package/dist/apiBasedTools.js +5 -3
- package/dist/index.d.ts +58 -0
- package/dist/index.js +251 -59
- package/dist/sanitizeSpeechText.d.ts +1 -0
- package/dist/surfaces/web-sse/createSseEventEmitter.d.ts +14 -0
- package/dist/surfaces/web-sse/createSseEventEmitter.js +196 -0
- package/dist/types.d.ts +94 -0
- package/index.ts +279 -59
- package/package.json +2 -2
- package/surfaces/web-sse/createSseEventEmitter.ts +261 -0
- package/tsconfig.json +2 -1
- package/types.ts +6 -0
package/dist/index.js
CHANGED
|
@@ -24,7 +24,7 @@ import { AdminForthCheckpointSaver } from "./agent/checkpointer.js";
|
|
|
24
24
|
import { createSequenceDebugCollector } from "./agent/middleware/sequenceDebug.js";
|
|
25
25
|
import { detectUserLanguage } from "./agent/languageDetect.js";
|
|
26
26
|
import { prepareApiBasedTools as buildApiBasedTools } from './apiBasedTools.js';
|
|
27
|
-
import {
|
|
27
|
+
import { createSseEventEmitter } from "./surfaces/web-sse/createSseEventEmitter.js";
|
|
28
28
|
import { appendCustomSystemPrompt, buildAgentSystemPrompt, buildAgentTurnSystemPrompt, DEFAULT_AGENT_SYSTEM_PROMPT } from "./agent/systemPrompt.js";
|
|
29
29
|
import { sanitizeSpeechText } from "./sanitizeSpeechText.js";
|
|
30
30
|
const agentResponseBodySchema = z.object({
|
|
@@ -57,6 +57,12 @@ function isAbortError(error) {
|
|
|
57
57
|
function getErrorMessage(error) {
|
|
58
58
|
return error instanceof Error ? error.message : String(error);
|
|
59
59
|
}
|
|
60
|
+
function requireAdminUser(adminUser) {
|
|
61
|
+
if (!adminUser) {
|
|
62
|
+
throw new Error("AdminForth Agent endpoint requires an authenticated admin user");
|
|
63
|
+
}
|
|
64
|
+
return adminUser;
|
|
65
|
+
}
|
|
60
66
|
export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
61
67
|
parseBody(schema, body, response) {
|
|
62
68
|
const parsed = schema.safeParse(body !== null && body !== void 0 ? body : {});
|
|
@@ -98,6 +104,25 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
98
104
|
}));
|
|
99
105
|
});
|
|
100
106
|
}
|
|
107
|
+
getChatSurfaceSessionId(incoming) {
|
|
108
|
+
return `${incoming.surface}:${incoming.externalConversationId}`;
|
|
109
|
+
}
|
|
110
|
+
getOrCreateChatSurfaceSession(incoming, adminUser) {
|
|
111
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
112
|
+
const sessionId = this.getChatSurfaceSessionId(incoming);
|
|
113
|
+
const sessionResource = this.adminforth.resource(this.options.sessionResource.resourceId);
|
|
114
|
+
const session = yield sessionResource.get([Filters.EQ(this.options.sessionResource.idField, sessionId)]);
|
|
115
|
+
if (session) {
|
|
116
|
+
return sessionId;
|
|
117
|
+
}
|
|
118
|
+
yield sessionResource.create({
|
|
119
|
+
[this.options.sessionResource.idField]: sessionId,
|
|
120
|
+
[this.options.sessionResource.titleField]: incoming.prompt.slice(0, 40) || "New Session",
|
|
121
|
+
[this.options.sessionResource.askerIdField]: adminUser.pk,
|
|
122
|
+
});
|
|
123
|
+
return sessionId;
|
|
124
|
+
});
|
|
125
|
+
}
|
|
101
126
|
getCheckpointer() {
|
|
102
127
|
if (this.checkpointer)
|
|
103
128
|
return this.checkpointer;
|
|
@@ -164,8 +189,11 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
164
189
|
});
|
|
165
190
|
}
|
|
166
191
|
validateConfigAfterDiscover(adminforth, resourceConfig) {
|
|
167
|
-
var _a;
|
|
192
|
+
var _a, _b;
|
|
168
193
|
(_a = this.options.audioAdapter) === null || _a === void 0 ? void 0 : _a.validate();
|
|
194
|
+
for (const chatSurfaceAdapter of (_b = this.options.chatSurfaceAdapters) !== null && _b !== void 0 ? _b : []) {
|
|
195
|
+
chatSurfaceAdapter.validate();
|
|
196
|
+
}
|
|
169
197
|
this.agentSystemPromptPromise = buildAgentSystemPrompt(adminforth, this.getInternalAgentResourceIds())
|
|
170
198
|
.then((systemPrompt) => appendCustomSystemPrompt(systemPrompt, this.options.systemPrompt));
|
|
171
199
|
}
|
|
@@ -175,7 +203,7 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
175
203
|
runAgentTurn(input) {
|
|
176
204
|
return __awaiter(this, void 0, void 0, function* () {
|
|
177
205
|
var _a, e_1, _b, _c;
|
|
178
|
-
var _d, _e, _f, _g, _h;
|
|
206
|
+
var _d, _e, _f, _g, _h, _j;
|
|
179
207
|
let fullResponse = "";
|
|
180
208
|
const maxTokens = (_d = this.options.maxTokens) !== null && _d !== void 0 ? _d : 1000;
|
|
181
209
|
const selectedMode = (_e = this.options.modes.find((mode) => mode.name === input.modeName)) !== null && _e !== void 0 ? _e : this.options.modes[0];
|
|
@@ -223,7 +251,7 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
223
251
|
adminUser: input.adminUser,
|
|
224
252
|
adminforth: this.adminforth,
|
|
225
253
|
apiBasedTools,
|
|
226
|
-
customComponentsDir: this.adminforth.config.customization.customComponentsDir,
|
|
254
|
+
customComponentsDir: (_f = this.adminforth.config.customization.customComponentsDir) !== null && _f !== void 0 ? _f : "custom",
|
|
227
255
|
sessionId: input.sessionId,
|
|
228
256
|
turnId: input.turnId,
|
|
229
257
|
currentPage: input.currentPage,
|
|
@@ -232,16 +260,19 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
232
260
|
emitToolCallEvent: (event) => {
|
|
233
261
|
var _a;
|
|
234
262
|
input.sequenceDebugCollector.handleToolCallEvent(event);
|
|
235
|
-
(_a = input.
|
|
263
|
+
void ((_a = input.emit) === null || _a === void 0 ? void 0 : _a.call(input, {
|
|
264
|
+
type: "tool-call",
|
|
265
|
+
data: event,
|
|
266
|
+
}));
|
|
236
267
|
},
|
|
237
268
|
sequenceDebugSink: input.sequenceDebugCollector,
|
|
238
269
|
});
|
|
239
270
|
try {
|
|
240
|
-
for (var
|
|
241
|
-
_c =
|
|
242
|
-
|
|
271
|
+
for (var _k = true, _l = __asyncValues(stream), _m; _m = yield _l.next(), _a = _m.done, !_a; _k = true) {
|
|
272
|
+
_c = _m.value;
|
|
273
|
+
_k = false;
|
|
243
274
|
const rawChunk = _c;
|
|
244
|
-
if ((
|
|
275
|
+
if ((_g = input.abortSignal) === null || _g === void 0 ? void 0 : _g.aborted) {
|
|
245
276
|
throw new DOMException("This operation was aborted", "AbortError");
|
|
246
277
|
}
|
|
247
278
|
const [token, metadata] = rawChunk;
|
|
@@ -265,18 +296,24 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
265
296
|
.map((b) => { var _a; return String((_a = b.text) !== null && _a !== void 0 ? _a : ""); })
|
|
266
297
|
.join("");
|
|
267
298
|
if (reasoningDelta) {
|
|
268
|
-
(
|
|
299
|
+
yield ((_h = input.emit) === null || _h === void 0 ? void 0 : _h.call(input, {
|
|
300
|
+
type: "reasoning-delta",
|
|
301
|
+
delta: reasoningDelta,
|
|
302
|
+
}));
|
|
269
303
|
}
|
|
270
304
|
if (textDelta) {
|
|
271
305
|
fullResponse += textDelta;
|
|
272
|
-
(
|
|
306
|
+
yield ((_j = input.emit) === null || _j === void 0 ? void 0 : _j.call(input, {
|
|
307
|
+
type: "text-delta",
|
|
308
|
+
delta: textDelta,
|
|
309
|
+
}));
|
|
273
310
|
}
|
|
274
311
|
}
|
|
275
312
|
}
|
|
276
313
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
277
314
|
finally {
|
|
278
315
|
try {
|
|
279
|
-
if (!
|
|
316
|
+
if (!_k && !_a && (_b = _l.return)) yield _b.call(_l);
|
|
280
317
|
}
|
|
281
318
|
finally { if (e_1) throw e_1.error; }
|
|
282
319
|
}
|
|
@@ -287,7 +324,7 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
287
324
|
}
|
|
288
325
|
runAndPersistAgentResponse(input) {
|
|
289
326
|
return __awaiter(this, void 0, void 0, function* () {
|
|
290
|
-
var _a
|
|
327
|
+
var _a;
|
|
291
328
|
const previousUserMessages = yield this.getPreviousUserMessages(input.sessionId);
|
|
292
329
|
const turnId = yield this.createNewTurn(input.sessionId, input.prompt);
|
|
293
330
|
yield this.adminforth.resource(this.options.sessionResource.resourceId).update(input.sessionId, {
|
|
@@ -309,9 +346,7 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
309
346
|
abortSignal: input.abortSignal,
|
|
310
347
|
adminUser: input.adminUser,
|
|
311
348
|
sequenceDebugCollector,
|
|
312
|
-
|
|
313
|
-
emitReasoningDelta: input.emitReasoningDelta,
|
|
314
|
-
emitTextDelta: input.emitTextDelta,
|
|
349
|
+
emit: input.emit,
|
|
315
350
|
});
|
|
316
351
|
fullResponse = agentResponse.text;
|
|
317
352
|
}
|
|
@@ -324,7 +359,6 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
324
359
|
failed = true;
|
|
325
360
|
fullResponse = getErrorMessage(error);
|
|
326
361
|
logger.error(`${input.failureLogMessage}:\n${fullResponse}`);
|
|
327
|
-
(_b = input.emitErrorResponse) === null || _b === void 0 ? void 0 : _b.call(input, fullResponse);
|
|
328
362
|
}
|
|
329
363
|
}
|
|
330
364
|
sequenceDebugCollector.flush();
|
|
@@ -343,18 +377,137 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
343
377
|
};
|
|
344
378
|
});
|
|
345
379
|
}
|
|
380
|
+
handleTurn(input) {
|
|
381
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
382
|
+
var _a, _b;
|
|
383
|
+
yield input.emit({
|
|
384
|
+
type: "turn-started",
|
|
385
|
+
messageId: randomUUID(),
|
|
386
|
+
});
|
|
387
|
+
const agentResponse = yield this.runAndPersistAgentResponse({
|
|
388
|
+
prompt: input.prompt,
|
|
389
|
+
sessionId: input.sessionId,
|
|
390
|
+
modeName: input.modeName,
|
|
391
|
+
userTimeZone: input.userTimeZone,
|
|
392
|
+
currentPage: input.currentPage,
|
|
393
|
+
abortSignal: input.abortSignal,
|
|
394
|
+
adminUser: input.adminUser,
|
|
395
|
+
emit: input.emit,
|
|
396
|
+
failureLogMessage: (_a = input.failureLogMessage) !== null && _a !== void 0 ? _a : "Agent response failed",
|
|
397
|
+
abortLogMessage: (_b = input.abortLogMessage) !== null && _b !== void 0 ? _b : "Agent response aborted",
|
|
398
|
+
});
|
|
399
|
+
if (agentResponse.failed) {
|
|
400
|
+
yield input.emit({
|
|
401
|
+
type: "error",
|
|
402
|
+
error: agentResponse.text,
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
else if (!agentResponse.aborted) {
|
|
406
|
+
yield input.emit({
|
|
407
|
+
type: "response",
|
|
408
|
+
text: agentResponse.text,
|
|
409
|
+
sessionId: input.sessionId,
|
|
410
|
+
turnId: agentResponse.turnId,
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
yield input.emit({
|
|
414
|
+
type: "finish",
|
|
415
|
+
});
|
|
416
|
+
return agentResponse;
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
createChatSurfaceEventEmitter(sink) {
|
|
420
|
+
return (event) => __awaiter(this, void 0, void 0, function* () {
|
|
421
|
+
if (event.type === "text-delta") {
|
|
422
|
+
yield sink.emit({
|
|
423
|
+
type: "text_delta",
|
|
424
|
+
delta: event.delta,
|
|
425
|
+
});
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
if (event.type === "response") {
|
|
429
|
+
yield sink.emit({
|
|
430
|
+
type: "done",
|
|
431
|
+
text: event.text,
|
|
432
|
+
});
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
if (event.type === "error") {
|
|
436
|
+
yield sink.emit({
|
|
437
|
+
type: "error",
|
|
438
|
+
message: event.error,
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
handleChatSurfaceMessage(adapter, incoming, sink) {
|
|
444
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
445
|
+
var _a;
|
|
446
|
+
const adminUser = yield adapter.resolveAdminUser({
|
|
447
|
+
adminforth: this.adminforth,
|
|
448
|
+
incoming,
|
|
449
|
+
});
|
|
450
|
+
if (!adminUser) {
|
|
451
|
+
yield sink.emit({
|
|
452
|
+
type: "error",
|
|
453
|
+
message: "This chat account is not authorized to use AdminForth Agent.",
|
|
454
|
+
});
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
yield this.handleTurn({
|
|
458
|
+
prompt: incoming.prompt,
|
|
459
|
+
sessionId: yield this.getOrCreateChatSurfaceSession(incoming, adminUser),
|
|
460
|
+
modeName: incoming.modeName,
|
|
461
|
+
userTimeZone: (_a = incoming.userTimeZone) !== null && _a !== void 0 ? _a : "UTC",
|
|
462
|
+
adminUser,
|
|
463
|
+
emit: this.createChatSurfaceEventEmitter(sink),
|
|
464
|
+
failureLogMessage: `Agent ${incoming.surface} surface response failed`,
|
|
465
|
+
abortLogMessage: `Agent ${incoming.surface} surface response aborted`,
|
|
466
|
+
});
|
|
467
|
+
});
|
|
468
|
+
}
|
|
346
469
|
setupEndpoints(server) {
|
|
470
|
+
var _a;
|
|
471
|
+
for (const adapter of (_a = this.options.chatSurfaceAdapters) !== null && _a !== void 0 ? _a : []) {
|
|
472
|
+
server.endpoint({
|
|
473
|
+
method: "POST",
|
|
474
|
+
noAuth: true,
|
|
475
|
+
path: `/agent/surface/${adapter.name}/webhook`,
|
|
476
|
+
handler: (ctx) => __awaiter(this, void 0, void 0, function* () {
|
|
477
|
+
var _a;
|
|
478
|
+
const surfaceContext = {
|
|
479
|
+
body: ctx.body,
|
|
480
|
+
headers: ctx.headers,
|
|
481
|
+
abortSignal: ctx.abortSignal,
|
|
482
|
+
rawRequest: ctx._raw_express_req,
|
|
483
|
+
rawResponse: ctx._raw_express_res,
|
|
484
|
+
};
|
|
485
|
+
const incoming = yield adapter.parseIncomingMessage(surfaceContext);
|
|
486
|
+
if (!incoming)
|
|
487
|
+
return { ok: true };
|
|
488
|
+
const sink = yield adapter.createEventSink(surfaceContext, incoming);
|
|
489
|
+
try {
|
|
490
|
+
yield this.handleChatSurfaceMessage(adapter, incoming, sink);
|
|
491
|
+
}
|
|
492
|
+
finally {
|
|
493
|
+
yield ((_a = sink.close) === null || _a === void 0 ? void 0 : _a.call(sink));
|
|
494
|
+
}
|
|
495
|
+
return { ok: true };
|
|
496
|
+
}),
|
|
497
|
+
});
|
|
498
|
+
}
|
|
347
499
|
server.endpoint({
|
|
348
500
|
method: 'POST',
|
|
349
501
|
path: `/agent/get-placeholder-messages`,
|
|
350
502
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ headers, adminUser }) {
|
|
503
|
+
const currentAdminUser = requireAdminUser(adminUser);
|
|
351
504
|
if (!this.options.placeholderMessages) {
|
|
352
505
|
return {
|
|
353
506
|
messages: [],
|
|
354
507
|
};
|
|
355
508
|
}
|
|
356
509
|
const messages = yield this.options.placeholderMessages({
|
|
357
|
-
adminUser,
|
|
510
|
+
adminUser: currentAdminUser,
|
|
358
511
|
headers,
|
|
359
512
|
});
|
|
360
513
|
return {
|
|
@@ -367,28 +520,26 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
367
520
|
path: `/agent/response`,
|
|
368
521
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response, _raw_express_res, abortSignal }) {
|
|
369
522
|
var _b;
|
|
523
|
+
const currentAdminUser = requireAdminUser(adminUser);
|
|
370
524
|
const data = this.parseBody(agentResponseBodySchema, body, response);
|
|
371
525
|
if (!data)
|
|
372
526
|
return;
|
|
373
|
-
const
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
527
|
+
const emit = createSseEventEmitter(_raw_express_res, {
|
|
528
|
+
vercelAiUiMessageStream: true,
|
|
529
|
+
closeActiveBlockOnToolStart: true,
|
|
530
|
+
});
|
|
531
|
+
yield this.handleTurn({
|
|
377
532
|
prompt: data.message,
|
|
378
533
|
sessionId: data.sessionId,
|
|
379
534
|
modeName: data.mode,
|
|
380
535
|
userTimeZone: (_b = data.timeZone) !== null && _b !== void 0 ? _b : 'UTC',
|
|
381
536
|
currentPage: data.currentPage,
|
|
382
537
|
abortSignal,
|
|
383
|
-
adminUser,
|
|
384
|
-
|
|
385
|
-
emitReasoningDelta: stream.reasoningDelta,
|
|
386
|
-
emitTextDelta: stream.textDelta,
|
|
387
|
-
emitErrorResponse: stream.textDelta,
|
|
538
|
+
adminUser: currentAdminUser,
|
|
539
|
+
emit,
|
|
388
540
|
failureLogMessage: "Agent response streaming failed",
|
|
389
541
|
abortLogMessage: "Agent response streaming aborted by the client",
|
|
390
542
|
});
|
|
391
|
-
stream.end();
|
|
392
543
|
return null;
|
|
393
544
|
})
|
|
394
545
|
});
|
|
@@ -398,20 +549,21 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
398
549
|
target: 'upload',
|
|
399
550
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response, _raw_express_req, _raw_express_res, abortSignal }) {
|
|
400
551
|
var _b;
|
|
552
|
+
const currentAdminUser = requireAdminUser(adminUser);
|
|
401
553
|
const req = _raw_express_req;
|
|
402
554
|
const audioAdapter = this.options.audioAdapter;
|
|
403
555
|
if (!audioAdapter) {
|
|
404
|
-
response.setStatus(400,
|
|
556
|
+
response.setStatus(400, "Audio adapter is not configured for AdminForth Agent");
|
|
405
557
|
return { error: "Audio adapter is not configured for AdminForth Agent" };
|
|
406
558
|
}
|
|
407
559
|
const data = this.parseBody(agentSpeechResponseBodySchema, body, response);
|
|
408
560
|
if (!data)
|
|
409
561
|
return;
|
|
410
562
|
if (!req.file) {
|
|
411
|
-
response.setStatus(400,
|
|
563
|
+
response.setStatus(400, "Audio file is required");
|
|
412
564
|
return { error: "Audio file is required" };
|
|
413
565
|
}
|
|
414
|
-
const
|
|
566
|
+
const emit = createSseEventEmitter(_raw_express_res);
|
|
415
567
|
let transcription;
|
|
416
568
|
try {
|
|
417
569
|
transcription = yield audioAdapter.transcribe({
|
|
@@ -425,25 +577,35 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
425
577
|
catch (error) {
|
|
426
578
|
if (abortSignal.aborted || isAbortError(error)) {
|
|
427
579
|
logger.info("Agent speech transcription aborted by the client");
|
|
428
|
-
|
|
580
|
+
yield emit({ type: "finish" });
|
|
429
581
|
return null;
|
|
430
582
|
}
|
|
431
583
|
logger.error(`Agent speech transcription failed:\n${getErrorMessage(error)}`);
|
|
432
|
-
|
|
433
|
-
|
|
584
|
+
yield emit({
|
|
585
|
+
type: "error",
|
|
586
|
+
error: "Speech transcription failed. Check server logs for details.",
|
|
587
|
+
});
|
|
588
|
+
yield emit({ type: "finish" });
|
|
434
589
|
return null;
|
|
435
590
|
}
|
|
436
591
|
if (abortSignal.aborted) {
|
|
437
|
-
|
|
592
|
+
yield emit({ type: "finish" });
|
|
438
593
|
return null;
|
|
439
594
|
}
|
|
440
595
|
const prompt = transcription.text;
|
|
441
596
|
if (!prompt) {
|
|
442
|
-
|
|
443
|
-
|
|
597
|
+
yield emit({
|
|
598
|
+
type: "error",
|
|
599
|
+
error: "Speech transcription is empty",
|
|
600
|
+
});
|
|
601
|
+
yield emit({ type: "finish" });
|
|
444
602
|
return null;
|
|
445
603
|
}
|
|
446
|
-
|
|
604
|
+
yield emit({
|
|
605
|
+
type: "transcript",
|
|
606
|
+
text: transcription.text,
|
|
607
|
+
language: transcription.language,
|
|
608
|
+
});
|
|
447
609
|
const sessionId = data.sessionId;
|
|
448
610
|
const currentPage = data.currentPage;
|
|
449
611
|
const agentResponse = yield this.runAndPersistAgentResponse({
|
|
@@ -453,27 +615,40 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
453
615
|
userTimeZone: (_b = data.timeZone) !== null && _b !== void 0 ? _b : 'UTC',
|
|
454
616
|
currentPage,
|
|
455
617
|
abortSignal,
|
|
456
|
-
adminUser,
|
|
457
|
-
|
|
618
|
+
adminUser: currentAdminUser,
|
|
619
|
+
emit: (event) => __awaiter(this, void 0, void 0, function* () {
|
|
620
|
+
if (event.type === "tool-call") {
|
|
621
|
+
yield emit(event);
|
|
622
|
+
}
|
|
623
|
+
}),
|
|
458
624
|
failureLogMessage: "Agent speech response failed",
|
|
459
625
|
abortLogMessage: "Agent speech response aborted by the client",
|
|
460
626
|
});
|
|
461
627
|
if (agentResponse.aborted) {
|
|
462
|
-
|
|
628
|
+
yield emit({ type: "finish" });
|
|
463
629
|
return null;
|
|
464
630
|
}
|
|
465
631
|
if (agentResponse.failed) {
|
|
466
|
-
|
|
467
|
-
|
|
632
|
+
yield emit({
|
|
633
|
+
type: "error",
|
|
634
|
+
error: agentResponse.text,
|
|
635
|
+
});
|
|
636
|
+
yield emit({ type: "finish" });
|
|
468
637
|
return null;
|
|
469
638
|
}
|
|
470
639
|
try {
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
640
|
+
yield emit({
|
|
641
|
+
type: "speech-response",
|
|
642
|
+
transcript: {
|
|
643
|
+
text: transcription.text,
|
|
644
|
+
language: transcription.language,
|
|
645
|
+
},
|
|
646
|
+
response: {
|
|
647
|
+
text: agentResponse.text,
|
|
648
|
+
},
|
|
649
|
+
sessionId,
|
|
650
|
+
turnId: agentResponse.turnId,
|
|
651
|
+
});
|
|
477
652
|
const speech = yield audioAdapter.synthesize({
|
|
478
653
|
text: sanitizeSpeechText(agentResponse.text),
|
|
479
654
|
stream: true,
|
|
@@ -481,7 +656,14 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
481
656
|
format: "pcm",
|
|
482
657
|
abortSignal,
|
|
483
658
|
});
|
|
484
|
-
|
|
659
|
+
yield emit({
|
|
660
|
+
type: "audio-start",
|
|
661
|
+
mimeType: speech.mimeType,
|
|
662
|
+
format: speech.format,
|
|
663
|
+
sampleRate: 24000,
|
|
664
|
+
channelCount: 1,
|
|
665
|
+
bitsPerSample: 16,
|
|
666
|
+
});
|
|
485
667
|
const reader = speech.audioStream.getReader();
|
|
486
668
|
const cancelAudioStream = () => {
|
|
487
669
|
void reader.cancel().catch(() => undefined);
|
|
@@ -500,15 +682,18 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
500
682
|
if (abortSignal.aborted) {
|
|
501
683
|
break;
|
|
502
684
|
}
|
|
503
|
-
|
|
685
|
+
yield emit({
|
|
686
|
+
type: "audio-delta",
|
|
687
|
+
value,
|
|
688
|
+
});
|
|
504
689
|
}
|
|
505
690
|
}
|
|
506
691
|
finally {
|
|
507
692
|
abortSignal.removeEventListener("abort", cancelAudioStream);
|
|
508
693
|
reader.releaseLock();
|
|
509
694
|
}
|
|
510
|
-
|
|
511
|
-
|
|
695
|
+
yield emit({ type: "audio-done" });
|
|
696
|
+
yield emit({ type: "finish" });
|
|
512
697
|
return null;
|
|
513
698
|
}
|
|
514
699
|
catch (error) {
|
|
@@ -517,9 +702,12 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
517
702
|
}
|
|
518
703
|
else {
|
|
519
704
|
logger.error(`Agent speech audio streaming failed:\n${error}`);
|
|
520
|
-
|
|
705
|
+
yield emit({
|
|
706
|
+
type: "error",
|
|
707
|
+
error: getErrorMessage(error),
|
|
708
|
+
});
|
|
521
709
|
}
|
|
522
|
-
|
|
710
|
+
yield emit({ type: "finish" });
|
|
523
711
|
return null;
|
|
524
712
|
}
|
|
525
713
|
})
|
|
@@ -529,10 +717,11 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
529
717
|
path: `/agent/get-sessions`,
|
|
530
718
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response }) {
|
|
531
719
|
var _b;
|
|
720
|
+
const currentAdminUser = requireAdminUser(adminUser);
|
|
532
721
|
const data = this.parseBody(getSessionsBodySchema, body, response);
|
|
533
722
|
if (!data)
|
|
534
723
|
return;
|
|
535
|
-
const userId =
|
|
724
|
+
const userId = currentAdminUser.pk;
|
|
536
725
|
const limit = (_b = data.limit) !== null && _b !== void 0 ? _b : 20;
|
|
537
726
|
const sessions = yield this.adminforth.resource(this.options.sessionResource.resourceId).list([Filters.EQ(this.options.sessionResource.askerIdField, userId)], limit, undefined, [Sorts.DESC(this.options.sessionResource.createdAtField)]);
|
|
538
727
|
return {
|
|
@@ -548,12 +737,13 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
548
737
|
method: 'POST',
|
|
549
738
|
path: `/agent/get-session-info`,
|
|
550
739
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response }) {
|
|
740
|
+
const currentAdminUser = requireAdminUser(adminUser);
|
|
551
741
|
const parsedBody = sessionIdBodySchema.safeParse(body);
|
|
552
742
|
if (!parsedBody.success) {
|
|
553
743
|
response.setStatus(422, parsedBody.error.message);
|
|
554
744
|
return;
|
|
555
745
|
}
|
|
556
|
-
const userId =
|
|
746
|
+
const userId = currentAdminUser.pk;
|
|
557
747
|
const sessionId = parsedBody.data.sessionId;
|
|
558
748
|
const session = yield this.adminforth.resource(this.options.sessionResource.resourceId).get([Filters.EQ(this.options.sessionResource.idField, sessionId)]);
|
|
559
749
|
if (!session) {
|
|
@@ -596,11 +786,12 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
596
786
|
method: 'POST',
|
|
597
787
|
path: `/agent/create-session`,
|
|
598
788
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response }) {
|
|
789
|
+
const currentAdminUser = requireAdminUser(adminUser);
|
|
599
790
|
const data = this.parseBody(createSessionBodySchema, body, response);
|
|
600
791
|
if (!data)
|
|
601
792
|
return;
|
|
602
793
|
const triggerMessage = data.triggerMessage;
|
|
603
|
-
const userId =
|
|
794
|
+
const userId = currentAdminUser.pk;
|
|
604
795
|
const title = (triggerMessage === null || triggerMessage === void 0 ? void 0 : triggerMessage.slice(0, 40)) || "New Session";
|
|
605
796
|
const newSession = {
|
|
606
797
|
[this.options.sessionResource.idField]: randomUUID(),
|
|
@@ -620,11 +811,12 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
620
811
|
method: 'POST',
|
|
621
812
|
path: `/agent/delete-session`,
|
|
622
813
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response }) {
|
|
814
|
+
const currentAdminUser = requireAdminUser(adminUser);
|
|
623
815
|
const data = this.parseBody(sessionIdBodySchema, body, response);
|
|
624
816
|
if (!data)
|
|
625
817
|
return;
|
|
626
818
|
const sessionId = data.sessionId;
|
|
627
|
-
const userId =
|
|
819
|
+
const userId = currentAdminUser.pk;
|
|
628
820
|
const session = yield this.adminforth.resource(this.options.sessionResource.resourceId).get([Filters.EQ(this.options.sessionResource.idField, sessionId)]);
|
|
629
821
|
if (!session) {
|
|
630
822
|
return {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function sanitizeSpeechText(input: string): string;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AgentEventEmitter } from "../../agentEvents.js";
|
|
2
|
+
type AgentEventStreamResponse = {
|
|
3
|
+
writeHead: (statusCode: number, headers: Record<string, string>) => void;
|
|
4
|
+
write: (chunk: string) => unknown;
|
|
5
|
+
end: () => unknown;
|
|
6
|
+
writableEnded: boolean;
|
|
7
|
+
destroyed: boolean;
|
|
8
|
+
};
|
|
9
|
+
type AgentEventStreamOptions = {
|
|
10
|
+
vercelAiUiMessageStream?: boolean;
|
|
11
|
+
closeActiveBlockOnToolStart?: boolean;
|
|
12
|
+
};
|
|
13
|
+
export declare function createSseEventEmitter(res: AgentEventStreamResponse, options?: AgentEventStreamOptions): AgentEventEmitter;
|
|
14
|
+
export {};
|