@adminforth/agent 2.0.10 → 2.2.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 (201) hide show
  1. package/README.md +333 -10
  2. package/dist/application/ports.d.ts +66 -0
  3. package/dist/application/runTurnUseCase.d.ts +71 -0
  4. package/dist/application/runTurnUseCase.js +364 -0
  5. package/dist/custom/ChatFooter.vue +58 -30
  6. package/dist/custom/SteerDebugPanel.vue +45 -0
  7. package/dist/custom/SteerQueue.vue +54 -0
  8. package/dist/custom/composables/agentStore/constants.ts +1 -0
  9. package/dist/custom/composables/agentStore/useAgentSessions.ts +35 -16
  10. package/dist/custom/composables/agentStore/useAgentSteerQueue.ts +114 -0
  11. package/dist/custom/composables/useAgentStore.ts +46 -1
  12. package/dist/custom/conversation_area/MessageRenderer.vue +7 -1
  13. package/dist/custom/speech_recognition_frontend/AudioLines.vue +1 -1
  14. package/dist/custom/speech_recognition_frontend/MicrophoneButon.vue +3 -3
  15. package/dist/{agentEvents.d.ts → domain/agentEvents.d.ts} +5 -1
  16. package/dist/domain/steerBuffer.d.ts +33 -0
  17. package/dist/domain/steerBuffer.js +51 -0
  18. package/dist/{agent → domain}/systemPrompt.js +1 -1
  19. package/dist/{agent/turn → domain}/turnTypes.d.ts +41 -37
  20. package/dist/{agent/turn/VegaLiteStreamBuffer.d.ts → domain/vegaLiteStreamBuffer.d.ts} +1 -1
  21. package/dist/index.d.ts +4 -2
  22. package/dist/index.js +49 -35
  23. package/dist/{agent/runtime/AgentContext.d.ts → llm/agentContext.d.ts} +3 -3
  24. package/dist/{agent/simpleAgent.d.ts → llm/agentModels.d.ts} +18 -16
  25. package/dist/llm/agentModels.js +65 -0
  26. package/dist/{agent/runtime/AgentRuntime.d.ts → llm/agentRuntime.d.ts} +14 -2
  27. package/dist/{agent/runtime/AgentRuntime.js → llm/agentRuntime.js} +41 -6
  28. package/dist/llm/langGraphLlm.d.ts +25 -0
  29. package/dist/llm/langGraphLlm.js +54 -0
  30. package/dist/{agent/middleware/apiBasedTools.d.ts → llm/middleware/apiToolsMiddleware.d.ts} +1 -1
  31. package/dist/{agent/middleware/apiBasedTools.js → llm/middleware/apiToolsMiddleware.js} +8 -14
  32. package/dist/{agent → llm}/middleware/sequenceDebug.d.ts +1 -1
  33. package/dist/llm/middleware/steerMiddleware.d.ts +21 -0
  34. package/dist/llm/middleware/steerMiddleware.js +50 -0
  35. package/dist/{agent/models/AgentModelFactory.d.ts → llm/modelFactory.d.ts} +1 -1
  36. package/dist/{agent/models/AgentModelFactory.js → llm/modelFactory.js} +1 -1
  37. package/dist/llm/streamAdapter.d.ts +18 -0
  38. package/dist/llm/streamAdapter.js +117 -0
  39. package/dist/{sessionStore.d.ts → persistence/sessionStore.d.ts} +19 -2
  40. package/dist/{sessionStore.js → persistence/sessionStore.js} +53 -0
  41. package/dist/{agent/tools/AgentToolProvider.d.ts → tools/agentToolProvider.d.ts} +1 -1
  42. package/dist/{agent/tools/AgentToolProvider.js → tools/agentToolProvider.js} +1 -1
  43. package/dist/{apiBasedTools.js → tools/apiBasedTools.js} +0 -3
  44. package/dist/{agent/tools → tools}/apiTool.d.ts +1 -1
  45. package/dist/{agent/tools → tools}/fetchSkill.js +1 -1
  46. package/dist/{agent/tools → tools}/fetchToolSchema.d.ts +1 -1
  47. package/dist/{agent/tools → tools}/index.d.ts +1 -1
  48. package/dist/{agent/tools → tools}/navigateUser.d.ts +3 -3
  49. package/dist/{endpoints → transport/http}/context.d.ts +12 -4
  50. package/dist/transport/http/context.js +1 -0
  51. package/dist/{endpoints/core.js → transport/http/coreEndpoints.js} +23 -3
  52. package/dist/{endpoints/sessions.js → transport/http/sessionEndpoints.js} +36 -1
  53. package/dist/transport/sse/sseWriter.d.ts +29 -0
  54. package/dist/{surfaces/web-sse/createSseEventEmitter.js → transport/sse/sseWriter.js} +27 -0
  55. package/dist/{chatSurfaceService.d.ts → transport/surfaces/chatSurfaceService.d.ts} +3 -3
  56. package/dist/{chatSurfaceService.js → transport/surfaces/chatSurfaceService.js} +7 -5
  57. package/dist/{agent/speech/SpeechTurnService.d.ts → transport/surfaces/speechTurnService.d.ts} +1 -1
  58. package/dist/{agent/speech/SpeechTurnService.js → transport/surfaces/speechTurnService.js} +2 -2
  59. package/dist/types.d.ts +10 -4
  60. package/package.json +11 -2
  61. package/.woodpecker/buildRelease.sh +0 -13
  62. package/.woodpecker/buildSlackNotify.sh +0 -46
  63. package/.woodpecker/release.yml +0 -57
  64. package/agent/checkpointer.ts +0 -329
  65. package/agent/languageDetect.ts +0 -92
  66. package/agent/middleware/apiBasedTools.ts +0 -174
  67. package/agent/middleware/openAiResponsesContinuation.ts +0 -92
  68. package/agent/middleware/sequenceDebug.ts +0 -429
  69. package/agent/models/AgentModeResolver.ts +0 -9
  70. package/agent/models/AgentModelFactory.ts +0 -28
  71. package/agent/runtime/AgentContext.ts +0 -30
  72. package/agent/runtime/AgentRuntime.ts +0 -89
  73. package/agent/simpleAgent.ts +0 -199
  74. package/agent/skills/registry.ts +0 -162
  75. package/agent/speech/SpeechTurnService.ts +0 -179
  76. package/agent/systemPrompt.ts +0 -133
  77. package/agent/toolCallEvents.ts +0 -135
  78. package/agent/tools/AgentToolProvider.ts +0 -28
  79. package/agent/tools/apiTool.ts +0 -66
  80. package/agent/tools/fetchSkill.ts +0 -68
  81. package/agent/tools/fetchToolSchema.ts +0 -47
  82. package/agent/tools/getUserLocation.ts +0 -45
  83. package/agent/tools/index.ts +0 -31
  84. package/agent/tools/navigateUser.ts +0 -210
  85. package/agent/turn/TurnContextBuilder.ts +0 -36
  86. package/agent/turn/TurnLifecycleService.ts +0 -47
  87. package/agent/turn/TurnPersistenceService.ts +0 -33
  88. package/agent/turn/TurnPromptBuilder.ts +0 -51
  89. package/agent/turn/TurnStreamConsumer.ts +0 -69
  90. package/agent/turn/VegaLiteStreamBuffer.ts +0 -90
  91. package/agent/turn/turnTypes.ts +0 -100
  92. package/agentEvents.ts +0 -75
  93. package/agentTurnService.ts +0 -314
  94. package/apiBasedTools.ts +0 -712
  95. package/build.log +0 -67
  96. package/chatSurfaceService.ts +0 -319
  97. package/custom/ChatFooter.vue +0 -173
  98. package/custom/ChatHeader.vue +0 -78
  99. package/custom/ChatSurface.vue +0 -160
  100. package/custom/CustomAutoScrollContainer.vue +0 -164
  101. package/custom/SessionsHistory.vue +0 -88
  102. package/custom/chat.ts +0 -82
  103. package/custom/composables/agentAudio/utils.ts +0 -220
  104. package/custom/composables/agentStore/constants.ts +0 -19
  105. package/custom/composables/agentStore/pageContext.ts +0 -8
  106. package/custom/composables/agentStore/useAgentChat.ts +0 -241
  107. package/custom/composables/agentStore/useAgentPlaceholder.ts +0 -142
  108. package/custom/composables/agentStore/useAgentSessions.ts +0 -350
  109. package/custom/composables/useAgentAudio.ts +0 -272
  110. package/custom/composables/useAgentStore.ts +0 -510
  111. package/custom/composables/useAgentTransitions.ts +0 -58
  112. package/custom/conversation_area/ConversationArea.vue +0 -301
  113. package/custom/conversation_area/MessageRenderer.vue +0 -49
  114. package/custom/conversation_area/ProcessingTimeline.vue +0 -286
  115. package/custom/conversation_area/ReasoningRenderer.vue +0 -79
  116. package/custom/conversation_area/SystemMessageRenderer.vue +0 -28
  117. package/custom/conversation_area/TextRenderer.vue +0 -182
  118. package/custom/conversation_area/ThreeDotsAnimation.vue +0 -35
  119. package/custom/conversation_area/ToolApprovalRenderer.vue +0 -98
  120. package/custom/conversation_area/ToolRenderer.vue +0 -178
  121. package/custom/conversation_area/ToolsGroup.vue +0 -59
  122. package/custom/env.d.ts +0 -7
  123. package/custom/incremark_code_renderers/IncremarkShikiCodeBlock.vue +0 -393
  124. package/custom/incremark_code_renderers/incremarkCodeHighlight.ts +0 -285
  125. package/custom/incremark_code_renderers/incremarkRenderer.ts +0 -653
  126. package/custom/incremark_code_renderers/renderIncremarkMarkdown.ts +0 -118
  127. package/custom/package.json +0 -30
  128. package/custom/pnpm-lock.yaml +0 -2394
  129. package/custom/public/agentAudio/agent-processing.mp3 +0 -0
  130. package/custom/skills/analyze_data/SKILL.md +0 -25
  131. package/custom/skills/charts/SKILL.md +0 -193
  132. package/custom/skills/fetch_data/SKILL.md +0 -31
  133. package/custom/skills/mutate_data/SKILL.md +0 -121
  134. package/custom/speech_recognition_frontend/AudioLines.vue +0 -43
  135. package/custom/speech_recognition_frontend/MicrophoneButon.vue +0 -185
  136. package/custom/speech_recognition_frontend/types/voice-activity-detection.d.ts +0 -22
  137. package/custom/speech_recognition_frontend/voiceActivityDetection.ts +0 -62
  138. package/custom/tsconfig.json +0 -15
  139. package/custom/types.ts +0 -108
  140. package/custom/utils.ts +0 -38
  141. package/dist/agent/middleware/openAiResponsesContinuation.d.ts +0 -1
  142. package/dist/agent/middleware/openAiResponsesContinuation.js +0 -66
  143. package/dist/agent/models/AgentModeResolver.d.ts +0 -9
  144. package/dist/agent/models/AgentModeResolver.js +0 -9
  145. package/dist/agent/simpleAgent.js +0 -118
  146. package/dist/agent/turn/TurnContextBuilder.d.ts +0 -14
  147. package/dist/agent/turn/TurnContextBuilder.js +0 -31
  148. package/dist/agent/turn/TurnLifecycleService.d.ts +0 -24
  149. package/dist/agent/turn/TurnLifecycleService.js +0 -47
  150. package/dist/agent/turn/TurnPersistenceService.d.ts +0 -13
  151. package/dist/agent/turn/TurnPersistenceService.js +0 -35
  152. package/dist/agent/turn/TurnPromptBuilder.d.ts +0 -19
  153. package/dist/agent/turn/TurnPromptBuilder.js +0 -43
  154. package/dist/agent/turn/TurnStreamConsumer.d.ts +0 -11
  155. package/dist/agent/turn/TurnStreamConsumer.js +0 -84
  156. package/dist/agentTurnService.d.ts +0 -24
  157. package/dist/agentTurnService.js +0 -269
  158. package/dist/surfaces/web-sse/createSseEventEmitter.d.ts +0 -14
  159. package/endpoints/chatSurfaces.ts +0 -66
  160. package/endpoints/context.ts +0 -52
  161. package/endpoints/core.ts +0 -181
  162. package/endpoints/sessions.ts +0 -183
  163. package/errors.ts +0 -10
  164. package/index.ts +0 -192
  165. package/pnpm-workspace.yaml +0 -4
  166. package/sanitizeSpeechText.ts +0 -32
  167. package/sessionStore.ts +0 -105
  168. package/surfaces/web-sse/createSseEventEmitter.ts +0 -311
  169. package/tsconfig.json +0 -14
  170. package/types.ts +0 -127
  171. /package/dist/{agent/turn/turnTypes.js → application/ports.js} +0 -0
  172. /package/dist/{agentEvents.js → domain/agentEvents.js} +0 -0
  173. /package/dist/{agent → domain}/languageDetect.d.ts +0 -0
  174. /package/dist/{agent → domain}/languageDetect.js +0 -0
  175. /package/dist/{agent → domain}/systemPrompt.d.ts +0 -0
  176. /package/dist/{agent → domain}/toolCallEvents.d.ts +0 -0
  177. /package/dist/{agent → domain}/toolCallEvents.js +0 -0
  178. /package/dist/{endpoints/context.js → domain/turnTypes.js} +0 -0
  179. /package/dist/{agent/turn/VegaLiteStreamBuffer.js → domain/vegaLiteStreamBuffer.js} +0 -0
  180. /package/dist/{agent/runtime/AgentContext.js → llm/agentContext.js} +0 -0
  181. /package/dist/{agent → llm}/middleware/sequenceDebug.js +0 -0
  182. /package/dist/{agent/checkpointer.d.ts → persistence/checkpointStore.d.ts} +0 -0
  183. /package/dist/{agent/checkpointer.js → persistence/checkpointStore.js} +0 -0
  184. /package/dist/{errors.d.ts → shared/errors.d.ts} +0 -0
  185. /package/dist/{errors.js → shared/errors.js} +0 -0
  186. /package/dist/{sanitizeSpeechText.d.ts → shared/sanitizeSpeechText.d.ts} +0 -0
  187. /package/dist/{sanitizeSpeechText.js → shared/sanitizeSpeechText.js} +0 -0
  188. /package/dist/{apiBasedTools.d.ts → tools/apiBasedTools.d.ts} +0 -0
  189. /package/dist/{agent/tools → tools}/apiTool.js +0 -0
  190. /package/dist/{agent/tools → tools}/fetchSkill.d.ts +0 -0
  191. /package/dist/{agent/tools → tools}/fetchToolSchema.js +0 -0
  192. /package/dist/{agent/tools → tools}/getUserLocation.d.ts +0 -0
  193. /package/dist/{agent/tools → tools}/getUserLocation.js +0 -0
  194. /package/dist/{agent/tools → tools}/index.js +0 -0
  195. /package/dist/{agent/tools → tools}/navigateUser.js +0 -0
  196. /package/dist/{agent → tools}/skills/registry.d.ts +0 -0
  197. /package/dist/{agent → tools}/skills/registry.js +0 -0
  198. /package/dist/{endpoints/chatSurfaces.d.ts → transport/http/chatSurfaceEndpoints.d.ts} +0 -0
  199. /package/dist/{endpoints/chatSurfaces.js → transport/http/chatSurfaceEndpoints.js} +0 -0
  200. /package/dist/{endpoints/core.d.ts → transport/http/coreEndpoints.d.ts} +0 -0
  201. /package/dist/{endpoints/sessions.d.ts → transport/http/sessionEndpoints.d.ts} +0 -0
@@ -1,210 +0,0 @@
1
- import { tool } from "langchain";
2
- import { z } from "zod";
3
- import type { CurrentPageContext } from "./getUserLocation.js";
4
- import type { AgentEventEmitter } from "../../agentEvents.js";
5
-
6
- const filterSchema = z.object({
7
- column: z.string().min(1).describe("Resource column name."),
8
- operator: z
9
- .string()
10
- .min(1)
11
- .describe("Filter operator suffix, for example eq, gte, lte, like, in."),
12
- value: z.unknown().describe("Filter value. Dates should be ISO strings."),
13
- });
14
-
15
- const navigateUserSchema = z
16
- .object({
17
- targetPath: z
18
- .string()
19
- .optional()
20
- .describe(
21
- "Root-relative AdminForth path to open, with optional query string and hash, for example /resource/adminuser?sort=created_at__desc.",
22
- ),
23
- resourceId: z
24
- .string()
25
- .optional()
26
- .describe("Resource id to build an AdminForth resource route for."),
27
- mode: z
28
- .enum(["list", "show", "edit", "create"])
29
- .optional()
30
- .default("list")
31
- .describe("Resource page mode. Defaults to list."),
32
- recordId: z
33
- .union([z.string(), z.number()])
34
- .optional()
35
- .describe("Record primary key for show or edit resource pages."),
36
- filters: z
37
- .array(filterSchema)
38
- .optional()
39
- .describe(
40
- "List page filters. Each item becomes filter__{column}__{operator}=JSON.stringify(value).",
41
- ),
42
- sort: z
43
- .object({
44
- column: z.string().min(1),
45
- direction: z.enum(["asc", "desc"]),
46
- })
47
- .optional()
48
- .describe("List page sort. Becomes sort={column}__{direction}."),
49
- query: z
50
- .record(z.string(), z.union([z.string(), z.number(), z.boolean()]))
51
- .optional()
52
- .describe("Additional query parameters to append to the target URL."),
53
- })
54
- .refine((input) => input.targetPath || input.resourceId, {
55
- message: "Either targetPath or resourceId is required.",
56
- });
57
-
58
- function normalizeTargetPath(targetPath: string, currentPage?: CurrentPageContext) {
59
- const trimmed = targetPath.trim();
60
-
61
- if (!trimmed) {
62
- throw new Error("targetPath cannot be empty.");
63
- }
64
-
65
- const currentOrigin = currentPage?.url ? new URL(currentPage.url).origin : undefined;
66
-
67
- if (currentOrigin) {
68
- const targetUrl = new URL(trimmed, currentOrigin);
69
-
70
- if (targetUrl.origin !== currentOrigin) {
71
- throw new Error("Only same-origin navigation targets are allowed.");
72
- }
73
-
74
- return `${targetUrl.pathname}${targetUrl.search}${targetUrl.hash}`;
75
- }
76
-
77
- const fallbackOrigin = "http://adminforth.local";
78
- const targetUrl = new URL(trimmed, fallbackOrigin);
79
-
80
- if (targetUrl.origin !== fallbackOrigin) {
81
- throw new Error("Only relative AdminForth paths are allowed when current origin is unavailable.");
82
- }
83
-
84
- return `${targetUrl.pathname}${targetUrl.search}${targetUrl.hash}`;
85
- }
86
-
87
- function appendQueryParams(path: string, params: URLSearchParams) {
88
- const queryString = params.toString();
89
-
90
- if (!queryString) {
91
- return path;
92
- }
93
-
94
- const hashIndex = path.indexOf("#");
95
- const pathWithoutHash = hashIndex === -1 ? path : path.slice(0, hashIndex);
96
- const hash = hashIndex === -1 ? "" : path.slice(hashIndex);
97
- const separator = pathWithoutHash.includes("?") ? "&" : "?";
98
-
99
- return `${pathWithoutHash}${separator}${queryString}${hash}`;
100
- }
101
-
102
- function buildResourcePath(input: z.infer<typeof navigateUserSchema>) {
103
- if (!input.resourceId) {
104
- throw new Error("resourceId is required to build a resource route.");
105
- }
106
-
107
- const resourceId = encodeURIComponent(input.resourceId);
108
- const mode = input.mode ?? "list";
109
-
110
- if (mode === "show" || mode === "edit") {
111
- if (input.recordId === undefined || input.recordId === null) {
112
- throw new Error(`recordId is required for ${mode} resource pages.`);
113
- }
114
-
115
- return `/resource/${resourceId}/${mode}/${encodeURIComponent(String(input.recordId))}`;
116
- }
117
-
118
- if (mode === "create") {
119
- return `/resource/${resourceId}/create`;
120
- }
121
-
122
- return `/resource/${resourceId}`;
123
- }
124
-
125
- function buildQueryParams(input: z.infer<typeof navigateUserSchema>) {
126
- const params = new URLSearchParams();
127
-
128
- for (const filter of input.filters ?? []) {
129
- params.set(
130
- `filter__${filter.column}__${filter.operator}`,
131
- JSON.stringify(filter.value),
132
- );
133
- }
134
-
135
- if (input.sort) {
136
- params.set("sort", `${input.sort.column}__${input.sort.direction}`);
137
- }
138
-
139
- for (const [key, value] of Object.entries(input.query ?? {})) {
140
- params.set(key, String(value));
141
- }
142
-
143
- return params;
144
- }
145
-
146
- function buildSurfaceUrl(targetPath: string, adminBaseUrl?: string, adminPublicOrigin?: string) {
147
- const normalizedBasePath = adminBaseUrl?.replace(/\/+$/, "") ?? "";
148
- const normalizedTargetPath = targetPath.replace(/^\/+/, "");
149
- const path = `${normalizedBasePath}/${normalizedTargetPath}`;
150
-
151
- return adminPublicOrigin ? new URL(path, adminPublicOrigin).toString() : path;
152
- }
153
-
154
- export function createNavigateUserTool() {
155
- return tool(
156
- async (input, runtime) => {
157
- const context = runtime.context as {
158
- currentPage?: CurrentPageContext;
159
- chatSurface?: string;
160
- adminBaseUrl?: string;
161
- adminPublicOrigin?: string;
162
- emit?: AgentEventEmitter;
163
- };
164
- const currentPage = context.currentPage;
165
- const basePath = input.targetPath
166
- ? normalizeTargetPath(input.targetPath, currentPage)
167
- : buildResourcePath(input);
168
- const targetPath = appendQueryParams(basePath, buildQueryParams(input));
169
-
170
- if (context.chatSurface) {
171
- const url = buildSurfaceUrl(targetPath, context.adminBaseUrl, context.adminPublicOrigin);
172
-
173
- return JSON.stringify(
174
- {
175
- status: 200,
176
- action: "link",
177
- surface: context.chatSurface,
178
- targetPath,
179
- url,
180
- message: `Send this link to the user: ${url}`,
181
- },
182
- null,
183
- 2,
184
- );
185
- }
186
-
187
- await context.emit?.({
188
- type: "open-page",
189
- targetPath,
190
- });
191
-
192
- return JSON.stringify(
193
- {
194
- status: 200,
195
- action: "navigate",
196
- targetPath,
197
- message: `Navigation requested to ${targetPath}.`,
198
- },
199
- null,
200
- 2,
201
- );
202
- },
203
- {
204
- name: "navigate_user",
205
- description:
206
- "Navigate the user to another AdminForth page. Use this only when the user asks to open, show, go to, or switch to a resource list/detail page, including filtered or sorted resource lists. Or if the user is asked to open something on the left. Do not use this tool in any other case.",
207
- schema: navigateUserSchema,
208
- },
209
- );
210
- }
@@ -1,36 +0,0 @@
1
- import type { AdminUser, IAdminForth } from "adminforth";
2
- import type { AgentTurnContext, BaseAgentTurnInput } from "./turnTypes.js";
3
-
4
- export type UserContextProvider = {
5
- getUserTimeZone(adminUser: AdminUser): Promise<string | null | undefined> | string | null | undefined;
6
- };
7
-
8
- export class TurnContextBuilder {
9
- constructor(
10
- private readonly getAdminforth: () => IAdminForth,
11
- private readonly userContextProvider?: UserContextProvider,
12
- ) {}
13
-
14
- async build(input: {
15
- base: BaseAgentTurnInput;
16
- turnId: string;
17
- }): Promise<AgentTurnContext> {
18
- const adminforth = this.getAdminforth();
19
-
20
- return {
21
- adminUser: input.base.adminUser,
22
- sessionId: input.base.sessionId,
23
- turnId: input.turnId,
24
- abortSignal: input.base.abortSignal,
25
- currentPage: input.base.currentPage,
26
- chatSurface: input.base.chatSurface,
27
- userTimeZone:
28
- input.base.userTimeZone
29
- ?? await this.userContextProvider?.getUserTimeZone(input.base.adminUser)
30
- ?? "UTC",
31
- adminPublicOrigin:
32
- input.base.adminPublicOrigin
33
- ?? adminforth.config.baseUrlSlashed,
34
- };
35
- }
36
- }
@@ -1,47 +0,0 @@
1
- import type { AgentSessionStore } from "../../sessionStore.js";
2
- import type { PluginOptions } from "../../types.js";
3
- import type { BaseAgentTurnInput } from "./turnTypes.js";
4
- import { TurnPersistenceService } from "./TurnPersistenceService.js";
5
-
6
- export class TurnLifecycleService {
7
- constructor(
8
- private readonly sessionStore: AgentSessionStore,
9
- private readonly persistence: TurnPersistenceService,
10
- private readonly options: PluginOptions,
11
- ) {}
12
-
13
- async start(input: BaseAgentTurnInput) {
14
- const previousUserMessages = await this.sessionStore.getPreviousUserMessages(input.sessionId);
15
- const turnId = await this.sessionStore.createNewTurn(input.sessionId, input.prompt);
16
- await this.persistence.touchSession(input.sessionId);
17
-
18
- return {
19
- turnId,
20
- previousUserMessages,
21
- };
22
- }
23
-
24
- async resume(input: BaseAgentTurnInput) {
25
- const latestTurn = await this.sessionStore.getLatestTurn(input.sessionId);
26
-
27
- if (!latestTurn) {
28
- throw new Error(`No agent turn found for session "${input.sessionId}".`);
29
- }
30
-
31
- return {
32
- turnId: latestTurn[this.options.turnResource.idField],
33
- previousUserMessages: await this.sessionStore.getPreviousUserMessages(input.sessionId),
34
- initialResponse: latestTurn[this.options.turnResource.responseField] === "not_finished"
35
- ? ""
36
- : String(latestTurn[this.options.turnResource.responseField]),
37
- };
38
- }
39
-
40
- async finish(input: {
41
- turnId: string;
42
- responseText: string;
43
- debugHistory?: unknown;
44
- }) {
45
- await this.persistence.saveTurnResponse(input);
46
- }
47
- }
@@ -1,33 +0,0 @@
1
- import type { IAdminForth } from "adminforth";
2
- import type { PluginOptions } from "../../types.js";
3
-
4
- export class TurnPersistenceService {
5
- constructor(
6
- private readonly getAdminforth: () => IAdminForth,
7
- private readonly options: PluginOptions,
8
- ) {}
9
-
10
- async touchSession(sessionId: string) {
11
- await this.getAdminforth().resource(this.options.sessionResource.resourceId).update(sessionId, {
12
- [this.options.sessionResource.createdAtField]: new Date().toISOString(),
13
- });
14
- }
15
-
16
- async saveTurnResponse(input: {
17
- turnId: string;
18
- responseText: string;
19
- debugHistory?: unknown;
20
- }) {
21
- const turnUpdates: Record<string, unknown> = {
22
- [this.options.turnResource.responseField]: input.responseText,
23
- };
24
-
25
- if (this.options.turnResource.debugField) {
26
- turnUpdates[this.options.turnResource.debugField] = input.debugHistory;
27
- }
28
-
29
- await this.getAdminforth()
30
- .resource(this.options.turnResource.resourceId)
31
- .update(input.turnId, turnUpdates);
32
- }
33
- }
@@ -1,51 +0,0 @@
1
- import type { AdminUser, IAdminForth } from "adminforth";
2
- import { logger } from "adminforth";
3
- import { HumanMessage, SystemMessage } from "langchain";
4
- import { detectUserLanguage, type PreviousUserMessage } from "../languageDetect.js";
5
- import { buildAgentTurnSystemPrompt } from "../systemPrompt.js";
6
- import { getErrorMessage, isAbortError } from "../../errors.js";
7
- import type { AgentModeCompletionAdapter } from "../simpleAgent.js";
8
-
9
- export class TurnPromptBuilder {
10
- constructor(
11
- private readonly options: {
12
- getAgentSystemPrompt: () => Promise<string>;
13
- getAdminforth: () => IAdminForth;
14
- },
15
- ) {}
16
-
17
- async build(input: {
18
- prompt: string;
19
- previousUserMessages: PreviousUserMessage[];
20
- adminUser: AdminUser;
21
- completionAdapter: AgentModeCompletionAdapter;
22
- chatSurface?: string;
23
- abortSignal?: AbortSignal;
24
- }) {
25
- const adminforth = this.options.getAdminforth();
26
- const userLanguage = await detectUserLanguage(
27
- input.completionAdapter,
28
- input.prompt,
29
- input.previousUserMessages,
30
- ).catch((error) => {
31
- if (input.abortSignal?.aborted || isAbortError(error)) {
32
- throw error;
33
- }
34
-
35
- logger.warn(`Failed to detect user language: ${getErrorMessage(error)}`);
36
- return null;
37
- });
38
- const systemPrompt = buildAgentTurnSystemPrompt({
39
- agentSystemPrompt: await this.options.getAgentSystemPrompt(),
40
- adminUser: input.adminUser,
41
- usernameField: adminforth.config.auth!.usernameField,
42
- userLanguage,
43
- chatSurface: input.chatSurface,
44
- });
45
-
46
- return [
47
- new SystemMessage(systemPrompt),
48
- new HumanMessage(input.prompt),
49
- ];
50
- }
51
- }
@@ -1,69 +0,0 @@
1
- import type { AgentEventEmitter } from "../../agentEvents.js";
2
- import { VegaLiteStreamBuffer } from "./VegaLiteStreamBuffer.js";
3
-
4
- export class TurnStreamConsumer {
5
- async consume(input: {
6
- stream: AsyncIterable<["messages", [any, any]] | ["updates", Record<string, any>]>;
7
- abortSignal?: AbortSignal;
8
- emit?: AgentEventEmitter;
9
- onInterrupt?: (interrupt: unknown) => void | Promise<void>;
10
- }) {
11
- let fullResponse = "";
12
- const textBuffer = new VegaLiteStreamBuffer();
13
-
14
- for await (const [mode, chunk] of input.stream) {
15
- if (input.abortSignal?.aborted) {
16
- throw new DOMException("This operation was aborted", "AbortError");
17
- }
18
-
19
- if (mode === "updates") {
20
- if ("__interrupt__" in chunk) {
21
- await input.onInterrupt?.(chunk.__interrupt__);
22
- }
23
- continue;
24
- }
25
-
26
- const [token, metadata] = chunk;
27
- const nodeName =
28
- typeof metadata?.langgraph_node === "string"
29
- ? metadata.langgraph_node
30
- : "";
31
-
32
- if (nodeName && !["model", "model_request"].includes(nodeName)) {
33
- continue;
34
- }
35
-
36
- const blocks = Array.isArray(token?.contentBlocks)
37
- ? token.contentBlocks
38
- : Array.isArray(token?.content)
39
- ? token.content
40
- : [];
41
- const reasoningDelta = blocks
42
- .filter((block: any) => block?.type === "reasoning")
43
- .map((block: any) => String(block.reasoning ?? ""))
44
- .join("");
45
- const textDelta = blocks
46
- .filter((block: any) => block?.type === "text")
47
- .map((block: any) => String(block.text ?? ""))
48
- .join("");
49
-
50
- if (reasoningDelta) {
51
- await input.emit?.({
52
- type: "reasoning-delta",
53
- delta: reasoningDelta,
54
- });
55
- }
56
-
57
- if (textDelta) {
58
- fullResponse += textDelta;
59
- await textBuffer.push(textDelta, input.emit);
60
- }
61
- }
62
-
63
- await textBuffer.flush(input.emit);
64
-
65
- return {
66
- text: fullResponse,
67
- };
68
- }
69
- }
@@ -1,90 +0,0 @@
1
- import type { AgentEventEmitter } from "../../agentEvents.js";
2
-
3
- const VEGA_LITE_FENCE_START = "```vega-lite";
4
- const FENCE_END = "```";
5
-
6
- export class VegaLiteStreamBuffer {
7
- private bufferedTextDelta = "";
8
- private isRenderingVegaLite = false;
9
-
10
- async push(textDelta: string, emit?: AgentEventEmitter) {
11
- this.bufferedTextDelta += textDelta;
12
-
13
- if (
14
- hasUnclosedLatestVegaLiteBlock(this.bufferedTextDelta)
15
- ) {
16
- if (!this.isRenderingVegaLite) {
17
- this.isRenderingVegaLite = true;
18
- await emit?.({
19
- type: "rendering",
20
- phase: "start",
21
- label: "Rendering...",
22
- });
23
- }
24
- return;
25
- }
26
-
27
- if (this.isRenderingVegaLite) {
28
- this.isRenderingVegaLite = false;
29
- await emit?.({
30
- type: "rendering",
31
- phase: "end",
32
- label: "Rendering...",
33
- });
34
- }
35
-
36
- const streamableLength = this.bufferedTextDelta.includes(VEGA_LITE_FENCE_START)
37
- ? this.bufferedTextDelta.length
38
- : this.bufferedTextDelta.length - getPartialVegaLiteFenceStartLength(this.bufferedTextDelta);
39
-
40
- if (!streamableLength) {
41
- return;
42
- }
43
-
44
- await emit?.({
45
- type: "text-delta",
46
- delta: this.bufferedTextDelta.slice(0, streamableLength),
47
- });
48
- this.bufferedTextDelta = this.bufferedTextDelta.slice(streamableLength);
49
- }
50
-
51
- async flush(emit?: AgentEventEmitter) {
52
- if (this.isRenderingVegaLite) {
53
- await emit?.({
54
- type: "rendering",
55
- phase: "end",
56
- label: "Rendering...",
57
- });
58
- this.isRenderingVegaLite = false;
59
- }
60
-
61
- if (this.bufferedTextDelta) {
62
- await emit?.({
63
- type: "text-delta",
64
- delta: this.bufferedTextDelta,
65
- });
66
- this.bufferedTextDelta = "";
67
- }
68
- }
69
- }
70
-
71
- function hasUnclosedLatestVegaLiteBlock(text: string): boolean {
72
- const latestBlockStart = text.lastIndexOf(VEGA_LITE_FENCE_START);
73
-
74
- if (latestBlockStart === -1) {
75
- return false;
76
- }
77
-
78
- const blockContentStart = latestBlockStart + VEGA_LITE_FENCE_START.length;
79
- return text.indexOf(FENCE_END, blockContentStart) === -1;
80
- }
81
-
82
- function getPartialVegaLiteFenceStartLength(text: string): number {
83
- for (let length = Math.min(text.length, VEGA_LITE_FENCE_START.length - 1); length > 0; length -= 1) {
84
- if (VEGA_LITE_FENCE_START.startsWith(text.slice(-length))) {
85
- return length;
86
- }
87
- }
88
-
89
- return 0;
90
- }
@@ -1,100 +0,0 @@
1
- import type { AdminUser, AudioAdapter } from "adminforth";
2
- import type { Messages } from "@langchain/langgraph";
3
- import type { Command } from "@langchain/langgraph";
4
- import type { AgentChatModel, AgentMiddleware } from "../simpleAgent.js";
5
- import type { SequenceDebugCollector } from "../middleware/sequenceDebug.js";
6
- import type { PreviousUserMessage } from "../languageDetect.js";
7
- import type { CurrentPageContext } from "../tools/getUserLocation.js";
8
- import type { AgentEventEmitter } from "../../agentEvents.js";
9
-
10
- export type BaseAgentTurnInput = {
11
- prompt: string;
12
- sessionId: string;
13
- modeName?: string | null;
14
- userTimeZone?: string;
15
- currentPage?: CurrentPageContext;
16
- chatSurface?: string;
17
- adminPublicOrigin?: string;
18
- abortSignal?: AbortSignal;
19
- adminUser: AdminUser;
20
- };
21
-
22
- export type TextAgentTurnInput = BaseAgentTurnInput & {
23
- emit: AgentEventEmitter;
24
- approvalDecision?: "approve" | "reject";
25
- failureLogMessage?: string;
26
- abortLogMessage?: string;
27
- };
28
-
29
- export type SpeechAgentTurnInput = Omit<BaseAgentTurnInput, "prompt"> & {
30
- emit: AgentEventEmitter;
31
- audioAdapter: AudioAdapter;
32
- audio: {
33
- buffer: Buffer;
34
- filename: string;
35
- mimeType: string;
36
- };
37
- failureLogMessage?: string;
38
- abortLogMessage?: string;
39
- };
40
-
41
- export type AgentTurnContext = {
42
- adminUser: AdminUser;
43
- userTimeZone: string;
44
- sessionId: string;
45
- turnId: string;
46
- abortSignal?: AbortSignal;
47
- currentPage?: CurrentPageContext;
48
- chatSurface?: string;
49
- adminPublicOrigin?: string;
50
- };
51
-
52
- export type AgentTurnObservability = {
53
- emit?: AgentEventEmitter;
54
- sequenceDebugSink: SequenceDebugCollector;
55
- };
56
-
57
- export type PreparedAgentTurn = {
58
- prompt: string;
59
- sessionId: string;
60
- turnId: string;
61
- previousUserMessages: PreviousUserMessage[];
62
- modeName?: string | null;
63
- context: AgentTurnContext;
64
- observability: AgentTurnObservability;
65
- resume?: {
66
- decision: "approve" | "reject";
67
- interrupts?: { id: string; count: number }[];
68
- };
69
- initialResponse?: string;
70
- };
71
-
72
- export type AgentTurnModels = {
73
- model: AgentChatModel;
74
- summaryModel: AgentChatModel;
75
- modelMiddleware?: AgentMiddleware[];
76
- };
77
-
78
- export type AgentRuntimeRunInput = {
79
- models: AgentTurnModels;
80
- input: { messages: Messages } | Command;
81
- context: AgentTurnContext;
82
- observability: AgentTurnObservability;
83
- };
84
-
85
- export type RunAndPersistAgentResponseInput = BaseAgentTurnInput & {
86
- emit?: AgentEventEmitter;
87
- approvalDecision?: "approve" | "reject";
88
- failureLogMessage: string;
89
- abortLogMessage: string;
90
- };
91
-
92
- export type RunAndPersistAgentResponseResult = {
93
- text: string;
94
- turnId: string;
95
- aborted: boolean;
96
- failed: boolean;
97
- };
98
-
99
- export type HandleTurnInput = TextAgentTurnInput;
100
- export type HandleSpeechTurnInput = SpeechAgentTurnInput;