@adminforth/agent 2.0.7 → 2.0.9
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/tools/apiTool.ts +1 -0
- package/build.log +1 -1
- package/dist/agent/tools/apiTool.js +1 -0
- package/dist/endpoints/context.d.ts +2 -7
- package/dist/endpoints/core.js +46 -11
- package/dist/endpoints/sessions.js +10 -15
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -9
- package/endpoints/context.ts +2 -8
- package/endpoints/core.ts +46 -8
- package/endpoints/sessions.ts +10 -10
- package/index.ts +0 -14
- package/package.json +3 -3
package/agent/tools/apiTool.ts
CHANGED
|
@@ -60,6 +60,7 @@ export function createApiTool(toolName: string, apiBasedTool: ApiBasedTool) {
|
|
|
60
60
|
name: toolName,
|
|
61
61
|
description: apiBasedTool.description ?? `${toolName} tool`,
|
|
62
62
|
schema: normalizeToolInputSchema(apiBasedTool.input_schema),
|
|
63
|
+
verboseParsingErrors: true,
|
|
63
64
|
},
|
|
64
65
|
);
|
|
65
66
|
}
|
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,682,
|
|
66
|
+
sent 1,682,452 bytes received 940 bytes 3,366,784.00 bytes/sec
|
|
67
67
|
total size is 1,678,191 speedup is 1.00
|
|
@@ -57,5 +57,6 @@ export function createApiTool(toolName, apiBasedTool) {
|
|
|
57
57
|
name: toolName,
|
|
58
58
|
description: (_a = apiBasedTool.description) !== null && _a !== void 0 ? _a : `${toolName} tool`,
|
|
59
59
|
schema: normalizeToolInputSchema(apiBasedTool.input_schema),
|
|
60
|
+
verboseParsingErrors: true,
|
|
60
61
|
});
|
|
61
62
|
}
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import type { ChatSurfaceAdapter, ChatSurfaceEventSink, ChatSurfaceIncomingMessage, IAdminForth } from "adminforth";
|
|
2
|
-
import type { ZodType } from "zod";
|
|
3
2
|
import type { HandleSpeechTurnInput, HandleTurnInput, RunAndPersistAgentResponseInput, RunAndPersistAgentResponseResult } from "../agentTurnService.js";
|
|
4
3
|
import type { PluginOptions } from "../types.js";
|
|
5
|
-
export type EndpointResponse = {
|
|
6
|
-
setStatus: (code: number, message: string) => void;
|
|
7
|
-
};
|
|
8
4
|
export type SessionTurn = {
|
|
9
5
|
prompt: string;
|
|
10
6
|
response: string;
|
|
@@ -12,7 +8,6 @@ export type SessionTurn = {
|
|
|
12
8
|
export type AgentEndpointsContext = {
|
|
13
9
|
adminforth: IAdminForth;
|
|
14
10
|
options: PluginOptions;
|
|
15
|
-
parseBody<T>(schema: ZodType<T>, body: unknown, response: EndpointResponse): T | null;
|
|
16
11
|
handleTurn(input: HandleTurnInput): Promise<RunAndPersistAgentResponseResult>;
|
|
17
12
|
handleSpeechTurn(input: HandleSpeechTurnInput): Promise<RunAndPersistAgentResponseResult | null>;
|
|
18
13
|
runAndPersistAgentResponse(input: RunAndPersistAgentResponseInput): Promise<RunAndPersistAgentResponseResult>;
|
|
@@ -21,6 +16,6 @@ export type AgentEndpointsContext = {
|
|
|
21
16
|
createSystemTurn(sessionId: string, systemMessage: string): Promise<string>;
|
|
22
17
|
handleChatSurfaceMessage(adapter: ChatSurfaceAdapter, incoming: ChatSurfaceIncomingMessage, sink: ChatSurfaceEventSink): Promise<void>;
|
|
23
18
|
};
|
|
24
|
-
export type CoreEndpointsContext = Pick<AgentEndpointsContext, "options" | "
|
|
25
|
-
export type SessionEndpointsContext = Pick<AgentEndpointsContext, "adminforth" | "options" | "
|
|
19
|
+
export type CoreEndpointsContext = Pick<AgentEndpointsContext, "options" | "handleTurn" | "handleSpeechTurn">;
|
|
20
|
+
export type SessionEndpointsContext = Pick<AgentEndpointsContext, "adminforth" | "options" | "getSessionTurns" | "createNewTurn" | "createSystemTurn">;
|
|
26
21
|
export type ChatSurfaceEndpointsContext = Pick<AgentEndpointsContext, "adminforth" | "options" | "handleChatSurfaceMessage">;
|
package/dist/endpoints/core.js
CHANGED
|
@@ -9,18 +9,51 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
};
|
|
10
10
|
import { z } from "zod";
|
|
11
11
|
import { createSseEventEmitter } from "../surfaces/web-sse/createSseEventEmitter.js";
|
|
12
|
+
const currentPageContextSchema = z.object({
|
|
13
|
+
path: z.string(),
|
|
14
|
+
fullPath: z.string(),
|
|
15
|
+
title: z.string(),
|
|
16
|
+
url: z.string(),
|
|
17
|
+
}).strict();
|
|
12
18
|
const agentResponseBodySchema = z.object({
|
|
13
19
|
message: z.string(),
|
|
14
20
|
sessionId: z.string(),
|
|
15
21
|
mode: z.string().nullish(),
|
|
16
22
|
timeZone: z.string().optional(),
|
|
17
|
-
currentPage:
|
|
23
|
+
currentPage: currentPageContextSchema.optional(),
|
|
18
24
|
}).strict();
|
|
19
25
|
const agentApprovalBodySchema = z.object({
|
|
20
26
|
sessionId: z.string(),
|
|
21
27
|
decision: z.enum(["approve", "reject"]),
|
|
22
28
|
}).strict();
|
|
23
|
-
|
|
29
|
+
// Sent as multipart/form-data (via multer), so every field arrives as a plain string on the wire.
|
|
30
|
+
// `currentPage` is JSON.stringify'd by the client into a form field and must be parsed back into
|
|
31
|
+
// an object. Zod -> JSON-Schema conversion cannot represent `.transform()` at all (it throws), so
|
|
32
|
+
// `agentSpeechResponseShapeSchema` (plain strings, no transform) is what's passed as request_schema
|
|
33
|
+
// for the AJV pre-check, while `agentSpeechResponseBodySchema` (with the transform) is used via an
|
|
34
|
+
// inline safeParse in the handler to actually parse `currentPage` into an object.
|
|
35
|
+
const agentSpeechResponseShapeSchema = z.object({
|
|
36
|
+
sessionId: z.string(),
|
|
37
|
+
mode: z.string().nullish(),
|
|
38
|
+
timeZone: z.string().optional(),
|
|
39
|
+
currentPage: z.string().optional(),
|
|
40
|
+
}).strict();
|
|
41
|
+
const agentSpeechResponseBodySchema = agentSpeechResponseShapeSchema.extend({
|
|
42
|
+
currentPage: z.string().optional().transform((value, ctx) => {
|
|
43
|
+
if (value === undefined)
|
|
44
|
+
return undefined;
|
|
45
|
+
try {
|
|
46
|
+
return currentPageContextSchema.parse(JSON.parse(value));
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
ctx.addIssue({
|
|
50
|
+
code: z.ZodIssueCode.custom,
|
|
51
|
+
message: `currentPage must be a JSON-encoded object matching CurrentPageContext: ${err instanceof Error ? err.message : String(err)}`,
|
|
52
|
+
});
|
|
53
|
+
return z.NEVER;
|
|
54
|
+
}
|
|
55
|
+
}),
|
|
56
|
+
});
|
|
24
57
|
export function setupCoreEndpoints(ctx, server) {
|
|
25
58
|
server.endpoint({
|
|
26
59
|
method: 'POST',
|
|
@@ -43,11 +76,10 @@ export function setupCoreEndpoints(ctx, server) {
|
|
|
43
76
|
server.endpoint({
|
|
44
77
|
method: 'POST',
|
|
45
78
|
path: `/agent/response`,
|
|
79
|
+
request_schema: agentResponseBodySchema,
|
|
46
80
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response, _raw_express_res, abortSignal }) {
|
|
47
81
|
var _b;
|
|
48
|
-
const data =
|
|
49
|
-
if (!data)
|
|
50
|
-
return;
|
|
82
|
+
const data = body;
|
|
51
83
|
const emit = createSseEventEmitter(_raw_express_res, {
|
|
52
84
|
vercelAiUiMessageStream: true,
|
|
53
85
|
closeActiveBlockOnToolStart: true,
|
|
@@ -70,10 +102,9 @@ export function setupCoreEndpoints(ctx, server) {
|
|
|
70
102
|
server.endpoint({
|
|
71
103
|
method: 'POST',
|
|
72
104
|
path: `/agent/approval`,
|
|
105
|
+
request_schema: agentApprovalBodySchema,
|
|
73
106
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response, _raw_express_res, abortSignal }) {
|
|
74
|
-
const data =
|
|
75
|
-
if (!data)
|
|
76
|
-
return;
|
|
107
|
+
const data = body;
|
|
77
108
|
const emit = createSseEventEmitter(_raw_express_res, {
|
|
78
109
|
vercelAiUiMessageStream: true,
|
|
79
110
|
closeActiveBlockOnToolStart: true,
|
|
@@ -95,6 +126,7 @@ export function setupCoreEndpoints(ctx, server) {
|
|
|
95
126
|
method: 'POST',
|
|
96
127
|
path: `/agent/speech-response`,
|
|
97
128
|
target: 'upload',
|
|
129
|
+
request_schema: agentSpeechResponseShapeSchema,
|
|
98
130
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response, _raw_express_req, _raw_express_res, abortSignal }) {
|
|
99
131
|
var _b;
|
|
100
132
|
const req = _raw_express_req;
|
|
@@ -103,9 +135,12 @@ export function setupCoreEndpoints(ctx, server) {
|
|
|
103
135
|
response.setStatus(400, "Audio adapter is not configured for AdminForth Agent");
|
|
104
136
|
return { error: "Audio adapter is not configured for AdminForth Agent" };
|
|
105
137
|
}
|
|
106
|
-
const
|
|
107
|
-
if (!
|
|
108
|
-
|
|
138
|
+
const parsed = agentSpeechResponseBodySchema.safeParse(body);
|
|
139
|
+
if (!parsed.success) {
|
|
140
|
+
response.setStatus(400, 'Request body validation failed');
|
|
141
|
+
return { error: 'Request body validation failed', details: parsed.error.issues };
|
|
142
|
+
}
|
|
143
|
+
const data = parsed.data;
|
|
109
144
|
if (!req.file) {
|
|
110
145
|
response.setStatus(400, "Audio file is required");
|
|
111
146
|
return { error: "Audio file is required" };
|
|
@@ -28,11 +28,10 @@ export function setupSessionEndpoints(ctx, server) {
|
|
|
28
28
|
server.endpoint({
|
|
29
29
|
method: 'POST',
|
|
30
30
|
path: `/agent/get-sessions`,
|
|
31
|
+
request_schema: getSessionsBodySchema,
|
|
31
32
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response }) {
|
|
32
33
|
var _b;
|
|
33
|
-
const data =
|
|
34
|
-
if (!data)
|
|
35
|
-
return;
|
|
34
|
+
const data = body;
|
|
36
35
|
const userId = adminUser.pk;
|
|
37
36
|
const limit = (_b = data.limit) !== null && _b !== void 0 ? _b : 20;
|
|
38
37
|
const sessions = yield ctx.adminforth.resource(ctx.options.sessionResource.resourceId).list([Filters.EQ(ctx.options.sessionResource.askerIdField, userId)], limit, undefined, [Sorts.DESC(ctx.options.sessionResource.createdAtField)]);
|
|
@@ -48,10 +47,9 @@ export function setupSessionEndpoints(ctx, server) {
|
|
|
48
47
|
server.endpoint({
|
|
49
48
|
method: 'POST',
|
|
50
49
|
path: `/agent/get-session-info`,
|
|
50
|
+
request_schema: sessionIdBodySchema,
|
|
51
51
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response }) {
|
|
52
|
-
const data =
|
|
53
|
-
if (!data)
|
|
54
|
-
return;
|
|
52
|
+
const data = body;
|
|
55
53
|
const userId = adminUser.pk;
|
|
56
54
|
const sessionId = data.sessionId;
|
|
57
55
|
const session = yield ctx.adminforth.resource(ctx.options.sessionResource.resourceId).get([Filters.EQ(ctx.options.sessionResource.idField, sessionId)]);
|
|
@@ -101,10 +99,9 @@ export function setupSessionEndpoints(ctx, server) {
|
|
|
101
99
|
server.endpoint({
|
|
102
100
|
method: 'POST',
|
|
103
101
|
path: `/agent/create-session`,
|
|
102
|
+
request_schema: createSessionBodySchema,
|
|
104
103
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response }) {
|
|
105
|
-
const data =
|
|
106
|
-
if (!data)
|
|
107
|
-
return;
|
|
104
|
+
const data = body;
|
|
108
105
|
const triggerMessage = data.triggerMessage;
|
|
109
106
|
const userId = adminUser.pk;
|
|
110
107
|
const title = (triggerMessage === null || triggerMessage === void 0 ? void 0 : triggerMessage.slice(0, 40)) || "New Session";
|
|
@@ -125,10 +122,9 @@ export function setupSessionEndpoints(ctx, server) {
|
|
|
125
122
|
server.endpoint({
|
|
126
123
|
method: 'POST',
|
|
127
124
|
path: `/agent/delete-session`,
|
|
125
|
+
request_schema: sessionIdBodySchema,
|
|
128
126
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response }) {
|
|
129
|
-
const data =
|
|
130
|
-
if (!data)
|
|
131
|
-
return;
|
|
127
|
+
const data = body;
|
|
132
128
|
const sessionId = data.sessionId;
|
|
133
129
|
const userId = adminUser.pk;
|
|
134
130
|
const session = yield ctx.adminforth.resource(ctx.options.sessionResource.resourceId).get([Filters.EQ(ctx.options.sessionResource.idField, sessionId)]);
|
|
@@ -153,10 +149,9 @@ export function setupSessionEndpoints(ctx, server) {
|
|
|
153
149
|
server.endpoint({
|
|
154
150
|
method: 'POST',
|
|
155
151
|
path: `/agent/add-system-message-to-turns`,
|
|
152
|
+
request_schema: addSystemMessageBodySchema,
|
|
156
153
|
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response }) {
|
|
157
|
-
const data =
|
|
158
|
-
if (!data)
|
|
159
|
-
return;
|
|
154
|
+
const data = body;
|
|
160
155
|
const session = yield ctx.adminforth.resource(ctx.options.sessionResource.resourceId).get([Filters.EQ(ctx.options.sessionResource.idField, data.sessionId)]);
|
|
161
156
|
if (!session) {
|
|
162
157
|
return {
|
package/dist/index.d.ts
CHANGED
|
@@ -12,7 +12,6 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
12
12
|
private agentTurnService;
|
|
13
13
|
private speechTurnService;
|
|
14
14
|
private chatSurfaceService;
|
|
15
|
-
private parseBody;
|
|
16
15
|
private getCheckpointer;
|
|
17
16
|
private getInternalAgentResourceIds;
|
|
18
17
|
constructor(options: PluginOptions);
|
package/dist/index.js
CHANGED
|
@@ -28,14 +28,6 @@ import { TurnPersistenceService } from "./agent/turn/TurnPersistenceService.js";
|
|
|
28
28
|
import { TurnPromptBuilder } from "./agent/turn/TurnPromptBuilder.js";
|
|
29
29
|
import { TurnStreamConsumer } from "./agent/turn/TurnStreamConsumer.js";
|
|
30
30
|
export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
31
|
-
parseBody(schema, body, response) {
|
|
32
|
-
const parsed = schema.safeParse(body !== null && body !== void 0 ? body : {});
|
|
33
|
-
if (!parsed.success) {
|
|
34
|
-
response.setStatus(422, parsed.error.message);
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
return parsed.data;
|
|
38
|
-
}
|
|
39
31
|
getCheckpointer() {
|
|
40
32
|
if (this.checkpointer)
|
|
41
33
|
return this.checkpointer;
|
|
@@ -147,7 +139,6 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
147
139
|
const endpointContext = {
|
|
148
140
|
adminforth: this.adminforth,
|
|
149
141
|
options: this.options,
|
|
150
|
-
parseBody: this.parseBody.bind(this),
|
|
151
142
|
handleTurn: this.agentTurnService.handleTurn.bind(this.agentTurnService),
|
|
152
143
|
handleSpeechTurn: this.speechTurnService.handle.bind(this.speechTurnService),
|
|
153
144
|
runAndPersistAgentResponse: this.agentTurnService.runAndPersistAgentResponse.bind(this.agentTurnService),
|
package/endpoints/context.ts
CHANGED
|
@@ -4,7 +4,6 @@ import type {
|
|
|
4
4
|
ChatSurfaceIncomingMessage,
|
|
5
5
|
IAdminForth,
|
|
6
6
|
} from "adminforth";
|
|
7
|
-
import type { ZodType } from "zod";
|
|
8
7
|
import type {
|
|
9
8
|
HandleSpeechTurnInput,
|
|
10
9
|
HandleTurnInput,
|
|
@@ -13,10 +12,6 @@ import type {
|
|
|
13
12
|
} from "../agentTurnService.js";
|
|
14
13
|
import type { PluginOptions } from "../types.js";
|
|
15
14
|
|
|
16
|
-
export type EndpointResponse = {
|
|
17
|
-
setStatus: (code: number, message: string) => void;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
15
|
export type SessionTurn = {
|
|
21
16
|
prompt: string;
|
|
22
17
|
response: string;
|
|
@@ -25,7 +20,6 @@ export type SessionTurn = {
|
|
|
25
20
|
export type AgentEndpointsContext = {
|
|
26
21
|
adminforth: IAdminForth;
|
|
27
22
|
options: PluginOptions;
|
|
28
|
-
parseBody<T>(schema: ZodType<T>, body: unknown, response: EndpointResponse): T | null;
|
|
29
23
|
handleTurn(input: HandleTurnInput): Promise<RunAndPersistAgentResponseResult>;
|
|
30
24
|
handleSpeechTurn(input: HandleSpeechTurnInput): Promise<RunAndPersistAgentResponseResult | null>;
|
|
31
25
|
runAndPersistAgentResponse(input: RunAndPersistAgentResponseInput): Promise<RunAndPersistAgentResponseResult>;
|
|
@@ -41,12 +35,12 @@ export type AgentEndpointsContext = {
|
|
|
41
35
|
|
|
42
36
|
export type CoreEndpointsContext = Pick<
|
|
43
37
|
AgentEndpointsContext,
|
|
44
|
-
"options" | "
|
|
38
|
+
"options" | "handleTurn" | "handleSpeechTurn"
|
|
45
39
|
>;
|
|
46
40
|
|
|
47
41
|
export type SessionEndpointsContext = Pick<
|
|
48
42
|
AgentEndpointsContext,
|
|
49
|
-
"adminforth" | "options" | "
|
|
43
|
+
"adminforth" | "options" | "getSessionTurns" | "createNewTurn"
|
|
50
44
|
| "createSystemTurn"
|
|
51
45
|
>;
|
|
52
46
|
|
package/endpoints/core.ts
CHANGED
|
@@ -12,12 +12,19 @@ type MulterFile = {
|
|
|
12
12
|
|
|
13
13
|
type ExpressMulterRequest = { file?: MulterFile };
|
|
14
14
|
|
|
15
|
+
const currentPageContextSchema = z.object({
|
|
16
|
+
path: z.string(),
|
|
17
|
+
fullPath: z.string(),
|
|
18
|
+
title: z.string(),
|
|
19
|
+
url: z.string(),
|
|
20
|
+
}).strict() satisfies z.ZodType<CurrentPageContext>;
|
|
21
|
+
|
|
15
22
|
const agentResponseBodySchema = z.object({
|
|
16
23
|
message: z.string(),
|
|
17
24
|
sessionId: z.string(),
|
|
18
25
|
mode: z.string().nullish(),
|
|
19
26
|
timeZone: z.string().optional(),
|
|
20
|
-
currentPage:
|
|
27
|
+
currentPage: currentPageContextSchema.optional(),
|
|
21
28
|
}).strict();
|
|
22
29
|
|
|
23
30
|
const agentApprovalBodySchema = z.object({
|
|
@@ -25,7 +32,33 @@ const agentApprovalBodySchema = z.object({
|
|
|
25
32
|
decision: z.enum(["approve", "reject"]),
|
|
26
33
|
}).strict();
|
|
27
34
|
|
|
28
|
-
|
|
35
|
+
// Sent as multipart/form-data (via multer), so every field arrives as a plain string on the wire.
|
|
36
|
+
// `currentPage` is JSON.stringify'd by the client into a form field and must be parsed back into
|
|
37
|
+
// an object. Zod -> JSON-Schema conversion cannot represent `.transform()` at all (it throws), so
|
|
38
|
+
// `agentSpeechResponseShapeSchema` (plain strings, no transform) is what's passed as request_schema
|
|
39
|
+
// for the AJV pre-check, while `agentSpeechResponseBodySchema` (with the transform) is used via an
|
|
40
|
+
// inline safeParse in the handler to actually parse `currentPage` into an object.
|
|
41
|
+
const agentSpeechResponseShapeSchema = z.object({
|
|
42
|
+
sessionId: z.string(),
|
|
43
|
+
mode: z.string().nullish(),
|
|
44
|
+
timeZone: z.string().optional(),
|
|
45
|
+
currentPage: z.string().optional(),
|
|
46
|
+
}).strict();
|
|
47
|
+
|
|
48
|
+
const agentSpeechResponseBodySchema = agentSpeechResponseShapeSchema.extend({
|
|
49
|
+
currentPage: z.string().optional().transform((value, ctx) => {
|
|
50
|
+
if (value === undefined) return undefined;
|
|
51
|
+
try {
|
|
52
|
+
return currentPageContextSchema.parse(JSON.parse(value));
|
|
53
|
+
} catch (err) {
|
|
54
|
+
ctx.addIssue({
|
|
55
|
+
code: z.ZodIssueCode.custom,
|
|
56
|
+
message: `currentPage must be a JSON-encoded object matching CurrentPageContext: ${err instanceof Error ? err.message : String(err)}`,
|
|
57
|
+
});
|
|
58
|
+
return z.NEVER;
|
|
59
|
+
}
|
|
60
|
+
}),
|
|
61
|
+
});
|
|
29
62
|
|
|
30
63
|
export function setupCoreEndpoints(ctx: CoreEndpointsContext, server: IHttpServer) {
|
|
31
64
|
server.endpoint({
|
|
@@ -52,9 +85,9 @@ export function setupCoreEndpoints(ctx: CoreEndpointsContext, server: IHttpServe
|
|
|
52
85
|
server.endpoint({
|
|
53
86
|
method: 'POST',
|
|
54
87
|
path: `/agent/response`,
|
|
88
|
+
request_schema: agentResponseBodySchema,
|
|
55
89
|
handler: async ({ body, adminUser, response, _raw_express_res, abortSignal }) => {
|
|
56
|
-
const data =
|
|
57
|
-
if (!data) return;
|
|
90
|
+
const data = body as z.infer<typeof agentResponseBodySchema>;
|
|
58
91
|
const emit = createSseEventEmitter(_raw_express_res, {
|
|
59
92
|
vercelAiUiMessageStream: true,
|
|
60
93
|
closeActiveBlockOnToolStart: true,
|
|
@@ -79,9 +112,9 @@ export function setupCoreEndpoints(ctx: CoreEndpointsContext, server: IHttpServe
|
|
|
79
112
|
server.endpoint({
|
|
80
113
|
method: 'POST',
|
|
81
114
|
path: `/agent/approval`,
|
|
115
|
+
request_schema: agentApprovalBodySchema,
|
|
82
116
|
handler: async ({ body, adminUser, response, _raw_express_res, abortSignal }) => {
|
|
83
|
-
const data =
|
|
84
|
-
if (!data) return;
|
|
117
|
+
const data = body as z.infer<typeof agentApprovalBodySchema>;
|
|
85
118
|
const emit = createSseEventEmitter(_raw_express_res, {
|
|
86
119
|
vercelAiUiMessageStream: true,
|
|
87
120
|
closeActiveBlockOnToolStart: true,
|
|
@@ -105,6 +138,7 @@ export function setupCoreEndpoints(ctx: CoreEndpointsContext, server: IHttpServe
|
|
|
105
138
|
method: 'POST',
|
|
106
139
|
path: `/agent/speech-response`,
|
|
107
140
|
target: 'upload',
|
|
141
|
+
request_schema: agentSpeechResponseShapeSchema,
|
|
108
142
|
handler: async ({ body, adminUser, response, _raw_express_req, _raw_express_res, abortSignal }) => {
|
|
109
143
|
const req = _raw_express_req as ExpressMulterRequest;
|
|
110
144
|
const audioAdapter = ctx.options.audioAdapter;
|
|
@@ -112,8 +146,12 @@ export function setupCoreEndpoints(ctx: CoreEndpointsContext, server: IHttpServe
|
|
|
112
146
|
response.setStatus(400, "Audio adapter is not configured for AdminForth Agent");
|
|
113
147
|
return { error: "Audio adapter is not configured for AdminForth Agent" };
|
|
114
148
|
}
|
|
115
|
-
const
|
|
116
|
-
if (!
|
|
149
|
+
const parsed = agentSpeechResponseBodySchema.safeParse(body);
|
|
150
|
+
if (!parsed.success) {
|
|
151
|
+
response.setStatus(400, 'Request body validation failed');
|
|
152
|
+
return { error: 'Request body validation failed', details: parsed.error.issues };
|
|
153
|
+
}
|
|
154
|
+
const data = parsed.data;
|
|
117
155
|
if (!req.file) {
|
|
118
156
|
response.setStatus(400, "Audio file is required");
|
|
119
157
|
return { error: "Audio file is required" };
|
package/endpoints/sessions.ts
CHANGED
|
@@ -26,9 +26,9 @@ export function setupSessionEndpoints(ctx: SessionEndpointsContext, server: IHtt
|
|
|
26
26
|
server.endpoint({
|
|
27
27
|
method: 'POST',
|
|
28
28
|
path: `/agent/get-sessions`,
|
|
29
|
+
request_schema: getSessionsBodySchema,
|
|
29
30
|
handler: async ({body, adminUser, response }) => {
|
|
30
|
-
const data =
|
|
31
|
-
if (!data) return;
|
|
31
|
+
const data = body as z.infer<typeof getSessionsBodySchema>;
|
|
32
32
|
const userId = adminUser!.pk;
|
|
33
33
|
const limit = data.limit ?? 20;
|
|
34
34
|
const sessions = await ctx.adminforth.resource(ctx.options.sessionResource.resourceId).list(
|
|
@@ -47,9 +47,9 @@ export function setupSessionEndpoints(ctx: SessionEndpointsContext, server: IHtt
|
|
|
47
47
|
server.endpoint({
|
|
48
48
|
method: 'POST',
|
|
49
49
|
path: `/agent/get-session-info`,
|
|
50
|
+
request_schema: sessionIdBodySchema,
|
|
50
51
|
handler: async ({body, adminUser, response }) => {
|
|
51
|
-
const data =
|
|
52
|
-
if (!data) return;
|
|
52
|
+
const data = body as z.infer<typeof sessionIdBodySchema>;
|
|
53
53
|
const userId = adminUser!.pk;
|
|
54
54
|
const sessionId = data.sessionId;
|
|
55
55
|
const session = await ctx.adminforth.resource(ctx.options.sessionResource.resourceId).get(
|
|
@@ -102,9 +102,9 @@ export function setupSessionEndpoints(ctx: SessionEndpointsContext, server: IHtt
|
|
|
102
102
|
server.endpoint({
|
|
103
103
|
method: 'POST',
|
|
104
104
|
path: `/agent/create-session`,
|
|
105
|
+
request_schema: createSessionBodySchema,
|
|
105
106
|
handler: async ({body, adminUser, response }) => {
|
|
106
|
-
const data =
|
|
107
|
-
if (!data) return;
|
|
107
|
+
const data = body as z.infer<typeof createSessionBodySchema>;
|
|
108
108
|
const triggerMessage = data.triggerMessage;
|
|
109
109
|
const userId = adminUser!.pk;
|
|
110
110
|
const title = triggerMessage?.slice(0, 40) || "New Session";
|
|
@@ -126,9 +126,9 @@ export function setupSessionEndpoints(ctx: SessionEndpointsContext, server: IHtt
|
|
|
126
126
|
server.endpoint({
|
|
127
127
|
method: 'POST',
|
|
128
128
|
path: `/agent/delete-session`,
|
|
129
|
+
request_schema: sessionIdBodySchema,
|
|
129
130
|
handler: async ({body, adminUser, response }) => {
|
|
130
|
-
const data =
|
|
131
|
-
if (!data) return;
|
|
131
|
+
const data = body as z.infer<typeof sessionIdBodySchema>;
|
|
132
132
|
const sessionId = data.sessionId;
|
|
133
133
|
const userId = adminUser!.pk;
|
|
134
134
|
const session = await ctx.adminforth.resource(ctx.options.sessionResource.resourceId).get(
|
|
@@ -158,9 +158,9 @@ export function setupSessionEndpoints(ctx: SessionEndpointsContext, server: IHtt
|
|
|
158
158
|
server.endpoint({
|
|
159
159
|
method: 'POST',
|
|
160
160
|
path: `/agent/add-system-message-to-turns`,
|
|
161
|
+
request_schema: addSystemMessageBodySchema,
|
|
161
162
|
handler: async ({body, adminUser, response }) => {
|
|
162
|
-
const data =
|
|
163
|
-
if (!data) return;
|
|
163
|
+
const data = body as z.infer<typeof addSystemMessageBodySchema>;
|
|
164
164
|
const session = await ctx.adminforth.resource(ctx.options.sessionResource.resourceId).get(
|
|
165
165
|
[Filters.EQ(ctx.options.sessionResource.idField, data.sessionId)]
|
|
166
166
|
);
|
package/index.ts
CHANGED
|
@@ -8,7 +8,6 @@ import { AdminForthPlugin } from "adminforth";
|
|
|
8
8
|
|
|
9
9
|
import type { PluginOptions } from './types.js';
|
|
10
10
|
import { MemorySaver, type BaseCheckpointSaver } from "@langchain/langgraph";
|
|
11
|
-
import { z } from "zod";
|
|
12
11
|
import { AdminForthCheckpointSaver } from "./agent/checkpointer.js";
|
|
13
12
|
import { appendCustomSystemPrompt, buildAgentSystemPrompt, DEFAULT_AGENT_SYSTEM_PROMPT} from "./agent/systemPrompt.js";
|
|
14
13
|
import { setupCoreEndpoints } from "./endpoints/core.js";
|
|
@@ -41,18 +40,6 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
41
40
|
private agentTurnService: AgentTurnService;
|
|
42
41
|
private speechTurnService: SpeechTurnService;
|
|
43
42
|
private chatSurfaceService: ChatSurfaceService;
|
|
44
|
-
private parseBody<T>(
|
|
45
|
-
schema: z.ZodType<T>,
|
|
46
|
-
body: unknown,
|
|
47
|
-
response: { setStatus: (code: number, message: string) => void },
|
|
48
|
-
): T | null {
|
|
49
|
-
const parsed = schema.safeParse(body ?? {});
|
|
50
|
-
if (!parsed.success) {
|
|
51
|
-
response.setStatus(422, parsed.error.message);
|
|
52
|
-
return null;
|
|
53
|
-
}
|
|
54
|
-
return parsed.data;
|
|
55
|
-
}
|
|
56
43
|
private getCheckpointer() {
|
|
57
44
|
if (this.checkpointer) return this.checkpointer;
|
|
58
45
|
|
|
@@ -189,7 +176,6 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
189
176
|
const endpointContext = {
|
|
190
177
|
adminforth: this.adminforth,
|
|
191
178
|
options: this.options,
|
|
192
|
-
parseBody: this.parseBody.bind(this),
|
|
193
179
|
handleTurn: this.agentTurnService.handleTurn.bind(this.agentTurnService),
|
|
194
180
|
handleSpeechTurn: this.speechTurnService.handle.bind(this.speechTurnService),
|
|
195
181
|
runAndPersistAgentResponse: this.agentTurnService.runAndPersistAgentResponse.bind(this.agentTurnService),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adminforth/agent",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.9",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"description": "AI agent plugin for AdminForth with tool-based workflows and persistent chat sessions",
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/node": "latest",
|
|
28
|
-
"adminforth": "^3.
|
|
28
|
+
"adminforth": "^3.8.2",
|
|
29
29
|
"semantic-release": "^24.2.1",
|
|
30
30
|
"semantic-release-slack-bot": "^4.0.2",
|
|
31
31
|
"typescript": "^5.7.3"
|
|
@@ -67,6 +67,6 @@
|
|
|
67
67
|
}
|
|
68
68
|
],
|
|
69
69
|
"peerDependencies": {
|
|
70
|
-
"adminforth": "^3.
|
|
70
|
+
"adminforth": "^3.8.2"
|
|
71
71
|
}
|
|
72
72
|
}
|