@adminforth/agent 1.51.1 → 1.52.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.
Files changed (50) hide show
  1. package/agent/middleware/apiBasedTools.ts +31 -25
  2. package/agent/runtime/AgentRuntime.ts +24 -3
  3. package/agent/systemPrompt.ts +3 -6
  4. package/agent/turn/TurnLifecycleService.ts +18 -0
  5. package/agent/turn/TurnStreamConsumer.ts +11 -3
  6. package/agent/turn/turnTypes.ts +9 -1
  7. package/agentEvents.ts +5 -0
  8. package/agentTurnService.ts +158 -12
  9. package/apiBasedTools.ts +7 -0
  10. package/build.log +3 -2
  11. package/custom/ChatFooter.vue +3 -2
  12. package/custom/composables/agentStore/useAgentChat.ts +169 -6
  13. package/custom/composables/agentStore/useAgentSessions.ts +3 -1
  14. package/custom/composables/useAgentStore.ts +87 -0
  15. package/custom/conversation_area/MessageRenderer.vue +6 -1
  16. package/custom/conversation_area/ToolApprovalRenderer.vue +98 -0
  17. package/custom/skills/mutate_data/SKILL.md +10 -36
  18. package/custom/types.ts +4 -1
  19. package/dist/agent/middleware/apiBasedTools.js +26 -25
  20. package/dist/agent/runtime/AgentRuntime.d.ts +1 -1
  21. package/dist/agent/runtime/AgentRuntime.js +18 -3
  22. package/dist/agent/systemPrompt.js +3 -6
  23. package/dist/agent/turn/TurnLifecycleService.d.ts +8 -1
  24. package/dist/agent/turn/TurnLifecycleService.js +17 -1
  25. package/dist/agent/turn/TurnStreamConsumer.d.ts +2 -1
  26. package/dist/agent/turn/TurnStreamConsumer.js +14 -8
  27. package/dist/agent/turn/turnTypes.d.ts +14 -1
  28. package/dist/agentEvents.d.ts +4 -0
  29. package/dist/agentTurnService.d.ts +1 -0
  30. package/dist/agentTurnService.js +132 -14
  31. package/dist/apiBasedTools.d.ts +5 -0
  32. package/dist/apiBasedTools.js +1 -0
  33. package/dist/custom/ChatFooter.vue +3 -2
  34. package/dist/custom/composables/agentStore/useAgentChat.ts +169 -6
  35. package/dist/custom/composables/agentStore/useAgentSessions.ts +3 -1
  36. package/dist/custom/composables/useAgentStore.ts +87 -0
  37. package/dist/custom/conversation_area/MessageRenderer.vue +6 -1
  38. package/dist/custom/conversation_area/ToolApprovalRenderer.vue +98 -0
  39. package/dist/custom/skills/mutate_data/SKILL.md +10 -36
  40. package/dist/custom/types.ts +4 -1
  41. package/dist/endpoints/core.js +28 -0
  42. package/dist/index.js +1 -1
  43. package/dist/sessionStore.d.ts +1 -0
  44. package/dist/sessionStore.js +6 -0
  45. package/dist/surfaces/web-sse/createSseEventEmitter.js +13 -0
  46. package/endpoints/core.ts +30 -0
  47. package/index.ts +1 -1
  48. package/package.json +3 -6
  49. package/sessionStore.ts +11 -0
  50. package/surfaces/web-sse/createSseEventEmitter.ts +14 -0
@@ -61,6 +61,12 @@ export class AgentSessionStore {
61
61
  }));
62
62
  });
63
63
  }
64
+ getLatestTurn(sessionId) {
65
+ return __awaiter(this, void 0, void 0, function* () {
66
+ const turns = yield this.getAdminforth().resource(this.options.turnResource.resourceId).list([Filters.EQ(this.options.turnResource.sessionIdField, sessionId)], 1, undefined, [Sorts.DESC(this.options.turnResource.createdAtField)]);
67
+ return turns[0];
68
+ });
69
+ }
64
70
  getChatSurfaceSessionId(incoming) {
65
71
  return `${incoming.surface}:${incoming.externalConversationId}`;
66
72
  }
@@ -88,6 +88,16 @@ function createAgentEventStream(res, options = {}) {
88
88
  },
89
89
  });
90
90
  },
91
+ interrupt(sessionId, interrupt) {
92
+ stream.endActiveBlock();
93
+ stream.send({
94
+ type: isAiUiMessageStream ? "data-interrupt" : "interrupt",
95
+ data: {
96
+ sessionId,
97
+ interrupt,
98
+ },
99
+ });
100
+ },
91
101
  openPage(targetPath) {
92
102
  stream.send({
93
103
  type: isAiUiMessageStream ? "data-open-page" : "open-page",
@@ -194,6 +204,9 @@ export function createSseEventEmitter(res, options = {}) {
194
204
  case "rendering":
195
205
  stream.rendering(event.phase, event.label);
196
206
  break;
207
+ case "interrupt":
208
+ stream.interrupt(event.sessionId, event.interrupt);
209
+ break;
197
210
  case "open-page":
198
211
  stream.openPage(event.targetPath);
199
212
  break;
package/endpoints/core.ts CHANGED
@@ -20,6 +20,11 @@ const agentResponseBodySchema = z.object({
20
20
  currentPage: z.custom<CurrentPageContext>().optional(),
21
21
  }).strict();
22
22
 
23
+ const agentApprovalBodySchema = z.object({
24
+ sessionId: z.string(),
25
+ decision: z.enum(["approve", "reject"]),
26
+ }).strict();
27
+
23
28
  const agentSpeechResponseBodySchema = agentResponseBodySchema.omit({ message: true });
24
29
 
25
30
  export function setupCoreEndpoints(ctx: CoreEndpointsContext, server: IHttpServer) {
@@ -71,6 +76,31 @@ export function setupCoreEndpoints(ctx: CoreEndpointsContext, server: IHttpServe
71
76
  }
72
77
  });
73
78
 
79
+ server.endpoint({
80
+ method: 'POST',
81
+ path: `/agent/approval`,
82
+ handler: async ({ body, adminUser, response, _raw_express_res, abortSignal }) => {
83
+ const data = ctx.parseBody(agentApprovalBodySchema, body, response);
84
+ if (!data) return;
85
+ const emit = createSseEventEmitter(_raw_express_res, {
86
+ vercelAiUiMessageStream: true,
87
+ closeActiveBlockOnToolStart: true,
88
+ });
89
+
90
+ await ctx.handleTurn({
91
+ prompt: "",
92
+ sessionId: data.sessionId,
93
+ approvalDecision: data.decision,
94
+ abortSignal,
95
+ adminUser: adminUser!,
96
+ emit,
97
+ failureLogMessage: "Agent approval response streaming failed",
98
+ abortLogMessage: "Agent approval response streaming aborted by the client",
99
+ });
100
+ return null;
101
+ }
102
+ });
103
+
74
104
  server.endpoint({
75
105
  method: 'POST',
76
106
  path: `/agent/speech-response`,
package/index.ts CHANGED
@@ -85,7 +85,7 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
85
85
  });
86
86
  const persistence = new TurnPersistenceService(() => this.adminforth, this.options);
87
87
  this.agentTurnService = new AgentTurnService(
88
- new TurnLifecycleService(this.sessionStore, persistence),
88
+ new TurnLifecycleService(this.sessionStore, persistence, this.options),
89
89
  new TurnContextBuilder(() => this.adminforth),
90
90
  new AgentModeResolver(this.options),
91
91
  new AgentModelFactory(this.options.maxTokens ?? 1000),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/agent",
3
- "version": "1.51.1",
3
+ "version": "1.52.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -25,7 +25,6 @@
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": "2.71.1",
29
28
  "semantic-release": "^24.2.1",
30
29
  "semantic-release-slack-bot": "^4.0.2",
31
30
  "typescript": "^5.7.3"
@@ -34,6 +33,7 @@
34
33
  "@langchain/core": "^1.1.40",
35
34
  "@langchain/langgraph": "^1.2.8",
36
35
  "@langchain/langgraph-checkpoint": "^1.0.1",
36
+ "adminforth": "2.72.0",
37
37
  "dayjs": "^1.11.20",
38
38
  "langchain": "^1.3.3",
39
39
  "multer": "^2.1.1",
@@ -65,8 +65,5 @@
65
65
  "name": "next",
66
66
  "prerelease": true
67
67
  }
68
- ],
69
- "peerDependencies": {
70
- "adminforth": "2.71.1"
71
- }
68
+ ]
72
69
  }
package/sessionStore.ts CHANGED
@@ -65,6 +65,17 @@ export class AgentSessionStore {
65
65
  }));
66
66
  }
67
67
 
68
+ async getLatestTurn(sessionId: string) {
69
+ const turns = await this.getAdminforth().resource(this.options.turnResource.resourceId).list(
70
+ [Filters.EQ(this.options.turnResource.sessionIdField, sessionId)],
71
+ 1,
72
+ undefined,
73
+ [Sorts.DESC(this.options.turnResource.createdAtField)]
74
+ );
75
+
76
+ return turns[0];
77
+ }
78
+
68
79
  getChatSurfaceSessionId(incoming: ChatSurfaceIncomingMessage) {
69
80
  return `${incoming.surface}:${incoming.externalConversationId}`;
70
81
  }
@@ -123,6 +123,17 @@ function createAgentEventStream(
123
123
  });
124
124
  },
125
125
 
126
+ interrupt(sessionId: string, interrupt: unknown) {
127
+ stream.endActiveBlock();
128
+ stream.send({
129
+ type: isAiUiMessageStream ? "data-interrupt" : "interrupt",
130
+ data: {
131
+ sessionId,
132
+ interrupt,
133
+ },
134
+ });
135
+ },
136
+
126
137
  openPage(targetPath: string) {
127
138
  stream.send({
128
139
  type: isAiUiMessageStream ? "data-open-page" : "open-page",
@@ -259,6 +270,9 @@ export function createSseEventEmitter(
259
270
  case "rendering":
260
271
  stream.rendering(event.phase, event.label);
261
272
  break;
273
+ case "interrupt":
274
+ stream.interrupt(event.sessionId, event.interrupt);
275
+ break;
262
276
  case "open-page":
263
277
  stream.openPage(event.targetPath);
264
278
  break;