@adminforth/agent 2.0.9 → 2.1.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 (187) hide show
  1. package/README.md +333 -10
  2. package/dist/application/ports.d.ts +66 -0
  3. package/dist/application/runTurnUseCase.d.ts +68 -0
  4. package/dist/application/runTurnUseCase.js +358 -0
  5. package/dist/{agentEvents.d.ts → domain/agentEvents.d.ts} +1 -1
  6. package/dist/{agent → domain}/systemPrompt.js +1 -1
  7. package/dist/{agent/turn → domain}/turnTypes.d.ts +41 -37
  8. package/dist/{agent/turn/VegaLiteStreamBuffer.d.ts → domain/vegaLiteStreamBuffer.d.ts} +1 -1
  9. package/dist/index.d.ts +3 -2
  10. package/dist/index.js +40 -35
  11. package/dist/{agent/runtime/AgentContext.d.ts → llm/agentContext.d.ts} +3 -3
  12. package/dist/{agent/simpleAgent.d.ts → llm/agentModels.d.ts} +18 -16
  13. package/dist/llm/agentModels.js +65 -0
  14. package/dist/{agent/runtime/AgentRuntime.d.ts → llm/agentRuntime.d.ts} +11 -2
  15. package/dist/{agent/runtime/AgentRuntime.js → llm/agentRuntime.js} +38 -6
  16. package/dist/llm/langGraphLlm.d.ts +25 -0
  17. package/dist/llm/langGraphLlm.js +54 -0
  18. package/dist/{agent/middleware/apiBasedTools.d.ts → llm/middleware/apiToolsMiddleware.d.ts} +1 -1
  19. package/dist/{agent/middleware/apiBasedTools.js → llm/middleware/apiToolsMiddleware.js} +8 -14
  20. package/dist/{agent → llm}/middleware/sequenceDebug.d.ts +1 -1
  21. package/dist/{agent/models/AgentModelFactory.d.ts → llm/modelFactory.d.ts} +1 -1
  22. package/dist/{agent/models/AgentModelFactory.js → llm/modelFactory.js} +1 -1
  23. package/dist/llm/streamAdapter.d.ts +18 -0
  24. package/dist/llm/streamAdapter.js +117 -0
  25. package/dist/{sessionStore.d.ts → persistence/sessionStore.d.ts} +12 -2
  26. package/dist/{sessionStore.js → persistence/sessionStore.js} +33 -0
  27. package/dist/{agent/tools/AgentToolProvider.d.ts → tools/agentToolProvider.d.ts} +1 -1
  28. package/dist/{agent/tools/AgentToolProvider.js → tools/agentToolProvider.js} +1 -1
  29. package/dist/{apiBasedTools.js → tools/apiBasedTools.js} +10 -6
  30. package/dist/{agent/tools → tools}/apiTool.d.ts +1 -1
  31. package/dist/{agent/tools → tools}/fetchSkill.js +1 -1
  32. package/dist/{agent/tools → tools}/fetchToolSchema.d.ts +1 -1
  33. package/dist/{agent/tools → tools}/index.d.ts +1 -1
  34. package/dist/{agent/tools → tools}/navigateUser.d.ts +3 -3
  35. package/dist/{endpoints → transport/http}/context.d.ts +2 -2
  36. package/dist/transport/http/context.js +1 -0
  37. package/dist/{endpoints/core.js → transport/http/coreEndpoints.js} +3 -3
  38. package/dist/{endpoints/sessions.js → transport/http/sessionEndpoints.js} +7 -1
  39. package/dist/transport/sse/sseWriter.d.ts +29 -0
  40. package/dist/{surfaces/web-sse/createSseEventEmitter.js → transport/sse/sseWriter.js} +15 -0
  41. package/dist/{chatSurfaceService.d.ts → transport/surfaces/chatSurfaceService.d.ts} +3 -3
  42. package/dist/{chatSurfaceService.js → transport/surfaces/chatSurfaceService.js} +7 -5
  43. package/dist/{agent/speech/SpeechTurnService.d.ts → transport/surfaces/speechTurnService.d.ts} +1 -1
  44. package/dist/{agent/speech/SpeechTurnService.js → transport/surfaces/speechTurnService.js} +2 -2
  45. package/dist/types.d.ts +10 -4
  46. package/package.json +11 -2
  47. package/.woodpecker/buildRelease.sh +0 -13
  48. package/.woodpecker/buildSlackNotify.sh +0 -46
  49. package/.woodpecker/release.yml +0 -57
  50. package/agent/checkpointer.ts +0 -329
  51. package/agent/languageDetect.ts +0 -92
  52. package/agent/middleware/apiBasedTools.ts +0 -174
  53. package/agent/middleware/openAiResponsesContinuation.ts +0 -92
  54. package/agent/middleware/sequenceDebug.ts +0 -429
  55. package/agent/models/AgentModeResolver.ts +0 -9
  56. package/agent/models/AgentModelFactory.ts +0 -28
  57. package/agent/runtime/AgentContext.ts +0 -30
  58. package/agent/runtime/AgentRuntime.ts +0 -89
  59. package/agent/simpleAgent.ts +0 -199
  60. package/agent/skills/registry.ts +0 -162
  61. package/agent/speech/SpeechTurnService.ts +0 -179
  62. package/agent/systemPrompt.ts +0 -133
  63. package/agent/toolCallEvents.ts +0 -135
  64. package/agent/tools/AgentToolProvider.ts +0 -28
  65. package/agent/tools/apiTool.ts +0 -66
  66. package/agent/tools/fetchSkill.ts +0 -68
  67. package/agent/tools/fetchToolSchema.ts +0 -47
  68. package/agent/tools/getUserLocation.ts +0 -45
  69. package/agent/tools/index.ts +0 -31
  70. package/agent/tools/navigateUser.ts +0 -210
  71. package/agent/turn/TurnContextBuilder.ts +0 -36
  72. package/agent/turn/TurnLifecycleService.ts +0 -47
  73. package/agent/turn/TurnPersistenceService.ts +0 -33
  74. package/agent/turn/TurnPromptBuilder.ts +0 -51
  75. package/agent/turn/TurnStreamConsumer.ts +0 -69
  76. package/agent/turn/VegaLiteStreamBuffer.ts +0 -90
  77. package/agent/turn/turnTypes.ts +0 -100
  78. package/agentEvents.ts +0 -75
  79. package/agentTurnService.ts +0 -314
  80. package/apiBasedTools.ts +0 -702
  81. package/build.log +0 -67
  82. package/chatSurfaceService.ts +0 -319
  83. package/custom/ChatFooter.vue +0 -173
  84. package/custom/ChatHeader.vue +0 -78
  85. package/custom/ChatSurface.vue +0 -160
  86. package/custom/CustomAutoScrollContainer.vue +0 -164
  87. package/custom/SessionsHistory.vue +0 -88
  88. package/custom/chat.ts +0 -82
  89. package/custom/composables/agentAudio/utils.ts +0 -220
  90. package/custom/composables/agentStore/constants.ts +0 -19
  91. package/custom/composables/agentStore/pageContext.ts +0 -8
  92. package/custom/composables/agentStore/useAgentChat.ts +0 -241
  93. package/custom/composables/agentStore/useAgentPlaceholder.ts +0 -142
  94. package/custom/composables/agentStore/useAgentSessions.ts +0 -350
  95. package/custom/composables/useAgentAudio.ts +0 -272
  96. package/custom/composables/useAgentStore.ts +0 -510
  97. package/custom/composables/useAgentTransitions.ts +0 -58
  98. package/custom/conversation_area/ConversationArea.vue +0 -301
  99. package/custom/conversation_area/MessageRenderer.vue +0 -49
  100. package/custom/conversation_area/ProcessingTimeline.vue +0 -286
  101. package/custom/conversation_area/ReasoningRenderer.vue +0 -79
  102. package/custom/conversation_area/SystemMessageRenderer.vue +0 -28
  103. package/custom/conversation_area/TextRenderer.vue +0 -182
  104. package/custom/conversation_area/ThreeDotsAnimation.vue +0 -35
  105. package/custom/conversation_area/ToolApprovalRenderer.vue +0 -98
  106. package/custom/conversation_area/ToolRenderer.vue +0 -178
  107. package/custom/conversation_area/ToolsGroup.vue +0 -59
  108. package/custom/env.d.ts +0 -7
  109. package/custom/incremark_code_renderers/IncremarkShikiCodeBlock.vue +0 -393
  110. package/custom/incremark_code_renderers/incremarkCodeHighlight.ts +0 -285
  111. package/custom/incremark_code_renderers/incremarkRenderer.ts +0 -653
  112. package/custom/incremark_code_renderers/renderIncremarkMarkdown.ts +0 -118
  113. package/custom/package.json +0 -30
  114. package/custom/pnpm-lock.yaml +0 -2394
  115. package/custom/public/agentAudio/agent-processing.mp3 +0 -0
  116. package/custom/skills/analyze_data/SKILL.md +0 -25
  117. package/custom/skills/charts/SKILL.md +0 -193
  118. package/custom/skills/fetch_data/SKILL.md +0 -31
  119. package/custom/skills/mutate_data/SKILL.md +0 -121
  120. package/custom/speech_recognition_frontend/AudioLines.vue +0 -43
  121. package/custom/speech_recognition_frontend/MicrophoneButon.vue +0 -185
  122. package/custom/speech_recognition_frontend/types/voice-activity-detection.d.ts +0 -22
  123. package/custom/speech_recognition_frontend/voiceActivityDetection.ts +0 -62
  124. package/custom/tsconfig.json +0 -15
  125. package/custom/types.ts +0 -108
  126. package/custom/utils.ts +0 -38
  127. package/dist/agent/middleware/openAiResponsesContinuation.d.ts +0 -1
  128. package/dist/agent/middleware/openAiResponsesContinuation.js +0 -66
  129. package/dist/agent/models/AgentModeResolver.d.ts +0 -9
  130. package/dist/agent/models/AgentModeResolver.js +0 -9
  131. package/dist/agent/simpleAgent.js +0 -118
  132. package/dist/agent/turn/TurnContextBuilder.d.ts +0 -14
  133. package/dist/agent/turn/TurnContextBuilder.js +0 -31
  134. package/dist/agent/turn/TurnLifecycleService.d.ts +0 -24
  135. package/dist/agent/turn/TurnLifecycleService.js +0 -47
  136. package/dist/agent/turn/TurnPersistenceService.d.ts +0 -13
  137. package/dist/agent/turn/TurnPersistenceService.js +0 -35
  138. package/dist/agent/turn/TurnPromptBuilder.d.ts +0 -19
  139. package/dist/agent/turn/TurnPromptBuilder.js +0 -43
  140. package/dist/agent/turn/TurnStreamConsumer.d.ts +0 -11
  141. package/dist/agent/turn/TurnStreamConsumer.js +0 -84
  142. package/dist/agentTurnService.d.ts +0 -24
  143. package/dist/agentTurnService.js +0 -269
  144. package/dist/surfaces/web-sse/createSseEventEmitter.d.ts +0 -14
  145. package/endpoints/chatSurfaces.ts +0 -66
  146. package/endpoints/context.ts +0 -52
  147. package/endpoints/core.ts +0 -181
  148. package/endpoints/sessions.ts +0 -183
  149. package/errors.ts +0 -10
  150. package/index.ts +0 -192
  151. package/pnpm-workspace.yaml +0 -4
  152. package/sanitizeSpeechText.ts +0 -32
  153. package/sessionStore.ts +0 -105
  154. package/surfaces/web-sse/createSseEventEmitter.ts +0 -311
  155. package/tsconfig.json +0 -14
  156. package/types.ts +0 -127
  157. /package/dist/{agent/turn/turnTypes.js → application/ports.js} +0 -0
  158. /package/dist/{agentEvents.js → domain/agentEvents.js} +0 -0
  159. /package/dist/{agent → domain}/languageDetect.d.ts +0 -0
  160. /package/dist/{agent → domain}/languageDetect.js +0 -0
  161. /package/dist/{agent → domain}/systemPrompt.d.ts +0 -0
  162. /package/dist/{agent → domain}/toolCallEvents.d.ts +0 -0
  163. /package/dist/{agent → domain}/toolCallEvents.js +0 -0
  164. /package/dist/{endpoints/context.js → domain/turnTypes.js} +0 -0
  165. /package/dist/{agent/turn/VegaLiteStreamBuffer.js → domain/vegaLiteStreamBuffer.js} +0 -0
  166. /package/dist/{agent/runtime/AgentContext.js → llm/agentContext.js} +0 -0
  167. /package/dist/{agent → llm}/middleware/sequenceDebug.js +0 -0
  168. /package/dist/{agent/checkpointer.d.ts → persistence/checkpointStore.d.ts} +0 -0
  169. /package/dist/{agent/checkpointer.js → persistence/checkpointStore.js} +0 -0
  170. /package/dist/{errors.d.ts → shared/errors.d.ts} +0 -0
  171. /package/dist/{errors.js → shared/errors.js} +0 -0
  172. /package/dist/{sanitizeSpeechText.d.ts → shared/sanitizeSpeechText.d.ts} +0 -0
  173. /package/dist/{sanitizeSpeechText.js → shared/sanitizeSpeechText.js} +0 -0
  174. /package/dist/{apiBasedTools.d.ts → tools/apiBasedTools.d.ts} +0 -0
  175. /package/dist/{agent/tools → tools}/apiTool.js +0 -0
  176. /package/dist/{agent/tools → tools}/fetchSkill.d.ts +0 -0
  177. /package/dist/{agent/tools → tools}/fetchToolSchema.js +0 -0
  178. /package/dist/{agent/tools → tools}/getUserLocation.d.ts +0 -0
  179. /package/dist/{agent/tools → tools}/getUserLocation.js +0 -0
  180. /package/dist/{agent/tools → tools}/index.js +0 -0
  181. /package/dist/{agent/tools → tools}/navigateUser.js +0 -0
  182. /package/dist/{agent → tools}/skills/registry.d.ts +0 -0
  183. /package/dist/{agent → tools}/skills/registry.js +0 -0
  184. /package/dist/{endpoints/chatSurfaces.d.ts → transport/http/chatSurfaceEndpoints.d.ts} +0 -0
  185. /package/dist/{endpoints/chatSurfaces.js → transport/http/chatSurfaceEndpoints.js} +0 -0
  186. /package/dist/{endpoints/core.d.ts → transport/http/coreEndpoints.d.ts} +0 -0
  187. /package/dist/{endpoints/sessions.d.ts → transport/http/sessionEndpoints.d.ts} +0 -0
@@ -0,0 +1,358 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ var __asyncValues = (this && this.__asyncValues) || function (o) {
11
+ if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
12
+ var m = o[Symbol.asyncIterator], i;
13
+ return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
14
+ function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
15
+ function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
16
+ };
17
+ import { logger } from "adminforth";
18
+ import { randomUUID } from "crypto";
19
+ import { VegaLiteStreamBuffer } from "../domain/vegaLiteStreamBuffer.js";
20
+ import { buildAgentTurnSystemPrompt } from "../domain/systemPrompt.js";
21
+ import { getErrorMessage, isAbortError } from "../shared/errors.js";
22
+ function getApprovalDecision(input) {
23
+ return "approvalDecision" in input
24
+ && (input.approvalDecision === "approve" || input.approvalDecision === "reject")
25
+ ? input.approvalDecision
26
+ : undefined;
27
+ }
28
+ function buildHitlDecision(decision, prompt) {
29
+ if (decision === "approve") {
30
+ return { type: "approve" };
31
+ }
32
+ return {
33
+ type: "reject",
34
+ message: prompt
35
+ ? `User rejected the pending tool execution and sent a new instruction instead: ${prompt}`
36
+ : "User rejected executing this tool",
37
+ };
38
+ }
39
+ function buildHitlResumeValue(input) {
40
+ return {
41
+ decisions: Array.from({ length: input.count }, () => (buildHitlDecision(input.decision, input.prompt))),
42
+ };
43
+ }
44
+ /**
45
+ * Build the provider-agnostic resume payload for a human-in-the-loop turn.
46
+ * Exported for unit testing; the LLM port wraps it into a LangGraph Command.
47
+ */
48
+ export function buildResumeValue(input) {
49
+ var _a;
50
+ const interrupts = (_a = input.interrupts) !== null && _a !== void 0 ? _a : [];
51
+ if (interrupts.length === 0) {
52
+ throw new Error("No pending approval interrupt found for resume.");
53
+ }
54
+ if (interrupts.length === 1) {
55
+ return buildHitlResumeValue({
56
+ decision: input.decision,
57
+ count: interrupts[0].count,
58
+ prompt: input.prompt,
59
+ });
60
+ }
61
+ return Object.fromEntries(interrupts.map((interrupt) => [
62
+ interrupt.id,
63
+ buildHitlResumeValue({
64
+ decision: input.decision,
65
+ count: interrupt.count,
66
+ prompt: input.prompt,
67
+ }),
68
+ ]));
69
+ }
70
+ /**
71
+ * Single entry point for running an agent turn: prepare (start/resume) → build
72
+ * the prompt → stream from the LLM port → consume the typed stream into SSE
73
+ * events → persist the result. Replaces the former AgentTurnService plus the
74
+ * TurnLifecycle/Context/Prompt/Persistence/StreamConsumer + ModeResolver stack.
75
+ */
76
+ export class RunTurnUseCase {
77
+ constructor(deps) {
78
+ this.deps = deps;
79
+ this.pendingInterrupts = new Map();
80
+ }
81
+ resolveMode(modeName) {
82
+ var _a;
83
+ return (_a = this.deps.modes.find((mode) => mode.name === modeName)) !== null && _a !== void 0 ? _a : this.deps.modes[0];
84
+ }
85
+ buildContext(input, turnId) {
86
+ var _a, _b;
87
+ return {
88
+ adminUser: input.adminUser,
89
+ sessionId: input.sessionId,
90
+ turnId,
91
+ abortSignal: input.abortSignal,
92
+ currentPage: input.currentPage,
93
+ chatSurface: input.chatSurface,
94
+ userTimeZone: (_a = input.userTimeZone) !== null && _a !== void 0 ? _a : "UTC",
95
+ adminPublicOrigin: (_b = input.adminPublicOrigin) !== null && _b !== void 0 ? _b : this.deps.getAdminforth().config.baseUrlSlashed,
96
+ };
97
+ }
98
+ /**
99
+ * Resolve the pending HITL interrupts for a resume. With a persistent checkpointer the
100
+ * checkpoint is authoritative (correct across instances and restarts); with the in-memory
101
+ * MemorySaver the in-process cache is authoritative (single process, cannot be stale).
102
+ */
103
+ resolvePendingInterrupts(sessionId, mode) {
104
+ return __awaiter(this, void 0, void 0, function* () {
105
+ var _a;
106
+ if (this.deps.hasPersistentCheckpointer) {
107
+ // The in-process cache can be stale after a cross-instance resume, so it is intentionally
108
+ // NOT consulted here. A failure to read the checkpoint is surfaced as a real error — never
109
+ // masked as "no pending approval".
110
+ try {
111
+ return yield this.deps.llm.getPendingInterrupts({
112
+ completionAdapter: mode.completionAdapter,
113
+ sessionId,
114
+ });
115
+ }
116
+ catch (error) {
117
+ logger.error(`Failed to read pending approval state from checkpoint for session "${sessionId}": ${getErrorMessage(error)}`);
118
+ throw error;
119
+ }
120
+ }
121
+ return (_a = this.pendingInterrupts.get(sessionId)) !== null && _a !== void 0 ? _a : [];
122
+ });
123
+ }
124
+ prepareTurn(input) {
125
+ return __awaiter(this, void 0, void 0, function* () {
126
+ const sequenceDebugSink = this.deps.createDebugSink();
127
+ const mode = this.resolveMode(input.modeName);
128
+ const approvalDecision = getApprovalDecision(input);
129
+ const shouldResume = Boolean(approvalDecision);
130
+ let turnId;
131
+ let previousUserMessages = [];
132
+ let initialResponse;
133
+ let resumeInterrupts;
134
+ if (shouldResume) {
135
+ resumeInterrupts = yield this.resolvePendingInterrupts(input.sessionId, mode);
136
+ if (resumeInterrupts.length === 0) {
137
+ throw new Error(`No pending approval interrupt found for session "${input.sessionId}".`);
138
+ }
139
+ const resumeState = yield this.deps.sessions.getResumeState(input.sessionId);
140
+ turnId = resumeState.turnId;
141
+ initialResponse = resumeState.initialResponse;
142
+ }
143
+ else {
144
+ previousUserMessages = yield this.deps.sessions.getPreviousUserMessages(input.sessionId);
145
+ turnId = yield this.deps.sessions.createNewTurn(input.sessionId, input.prompt);
146
+ yield this.deps.sessions.touchSession(input.sessionId);
147
+ }
148
+ return {
149
+ prompt: input.prompt,
150
+ sessionId: input.sessionId,
151
+ turnId,
152
+ previousUserMessages,
153
+ mode,
154
+ context: this.buildContext(input, turnId),
155
+ observability: {
156
+ emit: input.emit,
157
+ sequenceDebugSink,
158
+ },
159
+ resume: shouldResume
160
+ ? { decision: approvalDecision, interrupts: resumeInterrupts }
161
+ : undefined,
162
+ initialResponse,
163
+ };
164
+ });
165
+ }
166
+ buildMessages(prepared) {
167
+ return __awaiter(this, void 0, void 0, function* () {
168
+ const userLanguage = yield this.deps.llm
169
+ .detectLanguage({
170
+ completionAdapter: prepared.mode.completionAdapter,
171
+ prompt: prepared.prompt,
172
+ previousUserMessages: prepared.previousUserMessages,
173
+ })
174
+ .catch((error) => {
175
+ var _a;
176
+ if (((_a = prepared.context.abortSignal) === null || _a === void 0 ? void 0 : _a.aborted) || isAbortError(error)) {
177
+ throw error;
178
+ }
179
+ logger.warn(`Failed to detect user language: ${getErrorMessage(error)}`);
180
+ return null;
181
+ });
182
+ const adminforth = this.deps.getAdminforth();
183
+ const systemPrompt = buildAgentTurnSystemPrompt({
184
+ agentSystemPrompt: yield this.deps.getAgentSystemPrompt(),
185
+ adminUser: prepared.context.adminUser,
186
+ usernameField: adminforth.config.auth.usernameField,
187
+ userLanguage,
188
+ chatSurface: prepared.context.chatSurface,
189
+ });
190
+ return [
191
+ { role: "system", content: systemPrompt },
192
+ { role: "user", content: prepared.prompt },
193
+ ];
194
+ });
195
+ }
196
+ handleInterrupt(prepared, interrupt, descriptors) {
197
+ return __awaiter(this, void 0, void 0, function* () {
198
+ var _a, _b, _c;
199
+ if (!this.deps.hasPersistentCheckpointer) {
200
+ const existing = (_a = this.pendingInterrupts.get(prepared.sessionId)) !== null && _a !== void 0 ? _a : [];
201
+ const merged = new Map(existing.map((item) => [item.id, item.count]));
202
+ for (const item of descriptors) {
203
+ merged.set(item.id, item.count);
204
+ }
205
+ this.pendingInterrupts.set(prepared.sessionId, [...merged.entries()].map(([id, count]) => ({ id, count })));
206
+ }
207
+ yield ((_c = (_b = prepared.observability).emit) === null || _c === void 0 ? void 0 : _c.call(_b, {
208
+ type: "interrupt",
209
+ sessionId: prepared.sessionId,
210
+ interrupt,
211
+ }));
212
+ });
213
+ }
214
+ runAgentTurn(prepared) {
215
+ return __awaiter(this, void 0, void 0, function* () {
216
+ var _a, e_1, _b, _c;
217
+ const streamInput = prepared.resume
218
+ ? {
219
+ resume: buildResumeValue({
220
+ decision: prepared.resume.decision,
221
+ interrupts: prepared.resume.interrupts,
222
+ prompt: prepared.prompt,
223
+ }),
224
+ }
225
+ : { messages: yield this.buildMessages(prepared) };
226
+ const stream = yield this.deps.llm.streamTurn({
227
+ completionAdapter: prepared.mode.completionAdapter,
228
+ input: streamInput,
229
+ context: prepared.context,
230
+ observability: prepared.observability,
231
+ });
232
+ const { emit } = prepared.observability;
233
+ const abortSignal = prepared.context.abortSignal;
234
+ const textBuffer = new VegaLiteStreamBuffer();
235
+ let fullResponse = "";
236
+ let interrupted = false;
237
+ try {
238
+ try {
239
+ for (var _d = true, stream_1 = __asyncValues(stream), stream_1_1; stream_1_1 = yield stream_1.next(), _a = stream_1_1.done, !_a; _d = true) {
240
+ _c = stream_1_1.value;
241
+ _d = false;
242
+ const chunk = _c;
243
+ if (abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.aborted) {
244
+ throw new DOMException("This operation was aborted", "AbortError");
245
+ }
246
+ if (chunk.kind === "interrupt") {
247
+ interrupted = true;
248
+ yield this.handleInterrupt(prepared, chunk.interrupt, chunk.descriptors);
249
+ continue;
250
+ }
251
+ if (chunk.kind === "reasoning") {
252
+ if (chunk.delta) {
253
+ yield (emit === null || emit === void 0 ? void 0 : emit({ type: "reasoning-delta", delta: chunk.delta }));
254
+ }
255
+ continue;
256
+ }
257
+ if (chunk.delta) {
258
+ fullResponse += chunk.delta;
259
+ yield textBuffer.push(chunk.delta, emit);
260
+ }
261
+ }
262
+ }
263
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
264
+ finally {
265
+ try {
266
+ if (!_d && !_a && (_b = stream_1.return)) yield _b.call(stream_1);
267
+ }
268
+ finally { if (e_1) throw e_1.error; }
269
+ }
270
+ yield textBuffer.flush(emit);
271
+ return { text: fullResponse };
272
+ }
273
+ finally {
274
+ if (!this.deps.hasPersistentCheckpointer && !interrupted) {
275
+ this.pendingInterrupts.delete(prepared.sessionId);
276
+ }
277
+ }
278
+ });
279
+ }
280
+ runAndPersistAgentResponse(input) {
281
+ return __awaiter(this, void 0, void 0, function* () {
282
+ var _a, _b;
283
+ const prepared = yield this.prepareTurn(input);
284
+ let fullResponse = (_a = prepared.initialResponse) !== null && _a !== void 0 ? _a : "";
285
+ let aborted = false;
286
+ let failed = false;
287
+ try {
288
+ const agentResponse = yield this.runAgentTurn(prepared);
289
+ fullResponse += agentResponse.text;
290
+ }
291
+ catch (error) {
292
+ if (((_b = input.abortSignal) === null || _b === void 0 ? void 0 : _b.aborted) || isAbortError(error)) {
293
+ aborted = true;
294
+ logger.info(input.abortLogMessage);
295
+ }
296
+ else {
297
+ failed = true;
298
+ fullResponse = getErrorMessage(error);
299
+ logger.error(`${input.failureLogMessage}:\n${fullResponse}`);
300
+ }
301
+ }
302
+ prepared.observability.sequenceDebugSink.flush();
303
+ yield this.deps.sessions.saveTurnResponse({
304
+ turnId: prepared.turnId,
305
+ responseText: fullResponse,
306
+ debugHistory: prepared.observability.sequenceDebugSink.getHistory(),
307
+ });
308
+ return {
309
+ text: fullResponse,
310
+ turnId: prepared.turnId,
311
+ aborted,
312
+ failed,
313
+ };
314
+ });
315
+ }
316
+ handleTurn(input) {
317
+ return __awaiter(this, void 0, void 0, function* () {
318
+ var _a, _b;
319
+ yield input.emit({
320
+ type: "turn-started",
321
+ messageId: randomUUID(),
322
+ });
323
+ const agentResponse = yield this.runAndPersistAgentResponse({
324
+ prompt: input.prompt,
325
+ sessionId: input.sessionId,
326
+ modeName: input.modeName,
327
+ userTimeZone: input.userTimeZone,
328
+ currentPage: input.currentPage,
329
+ chatSurface: input.chatSurface,
330
+ adminPublicOrigin: input.adminPublicOrigin,
331
+ approvalDecision: input.approvalDecision,
332
+ abortSignal: input.abortSignal,
333
+ adminUser: input.adminUser,
334
+ emit: input.emit,
335
+ failureLogMessage: (_a = input.failureLogMessage) !== null && _a !== void 0 ? _a : "Agent response failed",
336
+ abortLogMessage: (_b = input.abortLogMessage) !== null && _b !== void 0 ? _b : "Agent response aborted",
337
+ });
338
+ if (agentResponse.failed) {
339
+ yield input.emit({
340
+ type: "error",
341
+ error: agentResponse.text,
342
+ });
343
+ }
344
+ else if (!agentResponse.aborted) {
345
+ yield input.emit({
346
+ type: "response",
347
+ text: agentResponse.text,
348
+ sessionId: input.sessionId,
349
+ turnId: agentResponse.turnId,
350
+ });
351
+ }
352
+ yield input.emit({
353
+ type: "finish",
354
+ });
355
+ return agentResponse;
356
+ });
357
+ }
358
+ }
@@ -1,4 +1,4 @@
1
- import type { ToolCallEvent } from "./agent/toolCallEvents.js";
1
+ import type { ToolCallEvent } from "./toolCallEvents.js";
2
2
  export type AgentEvent = {
3
3
  type: "turn-started";
4
4
  messageId: string;
@@ -7,7 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { listProjectSkillManifests, } from "./skills/registry.js";
10
+ import { listProjectSkillManifests, } from "../tools/skills/registry.js";
11
11
  export const DEFAULT_AGENT_SYSTEM_PROMPT = [
12
12
  "You are helpful AI Assistant for Admin Panel.",
13
13
  // about admin
@@ -1,11 +1,21 @@
1
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
2
  import type { CurrentPageContext } from "../tools/getUserLocation.js";
8
- import type { AgentEventEmitter } from "../../agentEvents.js";
3
+ import type { AgentEventEmitter } from "./agentEvents.js";
4
+ /**
5
+ * Minimal sink the application layer uses to persist per-turn debug traces. The
6
+ * concrete implementation (the sequence-debug collector) lives in the llm layer;
7
+ * the domain/application layers depend only on this narrow interface, so the
8
+ * dependency direction stays llm -> application/domain.
9
+ */
10
+ export type DebugSink = {
11
+ flush(): void;
12
+ getHistory(): unknown[];
13
+ };
14
+ /** A pending human-in-the-loop approval, normalized (provider-agnostic). */
15
+ export type PendingInterrupt = {
16
+ id: string;
17
+ count: number;
18
+ };
9
19
  export type BaseAgentTurnInput = {
10
20
  prompt: string;
11
21
  sessionId: string;
@@ -46,37 +56,7 @@ export type AgentTurnContext = {
46
56
  };
47
57
  export type AgentTurnObservability = {
48
58
  emit?: AgentEventEmitter;
49
- sequenceDebugSink: SequenceDebugCollector;
50
- };
51
- export type PreparedAgentTurn = {
52
- prompt: string;
53
- sessionId: string;
54
- turnId: string;
55
- previousUserMessages: PreviousUserMessage[];
56
- modeName?: string | null;
57
- context: AgentTurnContext;
58
- observability: AgentTurnObservability;
59
- resume?: {
60
- decision: "approve" | "reject";
61
- interrupts?: {
62
- id: string;
63
- count: number;
64
- }[];
65
- };
66
- initialResponse?: string;
67
- };
68
- export type AgentTurnModels = {
69
- model: AgentChatModel;
70
- summaryModel: AgentChatModel;
71
- modelMiddleware?: AgentMiddleware[];
72
- };
73
- export type AgentRuntimeRunInput = {
74
- models: AgentTurnModels;
75
- input: {
76
- messages: Messages;
77
- } | Command;
78
- context: AgentTurnContext;
79
- observability: AgentTurnObservability;
59
+ sequenceDebugSink: DebugSink;
80
60
  };
81
61
  export type RunAndPersistAgentResponseInput = BaseAgentTurnInput & {
82
62
  emit?: AgentEventEmitter;
@@ -92,3 +72,27 @@ export type RunAndPersistAgentResponseResult = {
92
72
  };
93
73
  export type HandleTurnInput = TextAgentTurnInput;
94
74
  export type HandleSpeechTurnInput = SpeechAgentTurnInput;
75
+ /**
76
+ * Provider-agnostic message passed from the application layer to the LLM port.
77
+ * The infrastructure adapter maps it onto concrete LangChain messages.
78
+ */
79
+ export type AgentMessage = {
80
+ role: "system" | "user";
81
+ content: string;
82
+ };
83
+ /**
84
+ * Normalized unit of a streamed agent turn. The LLM port converts the raw
85
+ * LangGraph stream into these typed chunks so the application layer never
86
+ * touches LangGraph's tuple/`any` stream shape.
87
+ */
88
+ export type AgentStreamChunk = {
89
+ kind: "text";
90
+ delta: string;
91
+ } | {
92
+ kind: "reasoning";
93
+ delta: string;
94
+ } | {
95
+ kind: "interrupt";
96
+ interrupt: unknown;
97
+ descriptors: PendingInterrupt[];
98
+ };
@@ -1,4 +1,4 @@
1
- import type { AgentEventEmitter } from "../../agentEvents.js";
1
+ import type { AgentEventEmitter } from "./agentEvents.js";
2
2
  export declare class VegaLiteStreamBuffer {
3
3
  private bufferedTextDelta;
4
4
  private isRenderingVegaLite;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { AdminForthResource, IAdminForth, IHttpServer } from "adminforth";
2
2
  import { AdminForthPlugin } from "adminforth";
3
3
  import type { PluginOptions } from './types.js';
4
- export type { AgentEvent, AgentEventEmitter } from "./agentEvents.js";
4
+ export type { AgentEvent, AgentEventEmitter } from "./domain/agentEvents.js";
5
5
  export default class AdminForthAgentPlugin extends AdminForthPlugin {
6
6
  options: PluginOptions;
7
7
  agentSystemPromptPromise: Promise<string>;
@@ -9,11 +9,12 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
9
9
  private agentSystemPrompt;
10
10
  private checkpointer;
11
11
  private sessionStore;
12
- private agentTurnService;
12
+ private runTurnUseCase;
13
13
  private speechTurnService;
14
14
  private chatSurfaceService;
15
15
  private getCheckpointer;
16
16
  private getInternalAgentResourceIds;
17
+ private getAgentSystemPrompt;
17
18
  constructor(options: PluginOptions);
18
19
  modifyGlobalConfig(adminforth: IAdminForth): Promise<void>;
19
20
  validateConfigAfterDiscover(adminforth: IAdminForth, resourceConfig: AdminForthResource): void;
package/dist/index.js CHANGED
@@ -7,26 +7,22 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { AdminForthPlugin } from "adminforth";
10
+ import { AdminForthPlugin, logger } from "adminforth";
11
11
  import { MemorySaver } from "@langchain/langgraph";
12
- import { AdminForthCheckpointSaver } from "./agent/checkpointer.js";
13
- import { appendCustomSystemPrompt, buildAgentSystemPrompt, DEFAULT_AGENT_SYSTEM_PROMPT } from "./agent/systemPrompt.js";
14
- import { setupCoreEndpoints } from "./endpoints/core.js";
15
- import { setupSessionEndpoints } from "./endpoints/sessions.js";
16
- import { setupChatSurfaceEndpoints } from "./endpoints/chatSurfaces.js";
17
- import { AgentSessionStore } from "./sessionStore.js";
18
- import { ChatSurfaceService } from "./chatSurfaceService.js";
19
- import { AgentTurnService } from "./agentTurnService.js";
20
- import { AgentModelFactory } from "./agent/models/AgentModelFactory.js";
21
- import { AgentModeResolver } from "./agent/models/AgentModeResolver.js";
22
- import { AgentRuntime } from "./agent/runtime/AgentRuntime.js";
23
- import { SpeechTurnService } from "./agent/speech/SpeechTurnService.js";
24
- import { AgentToolProvider } from "./agent/tools/AgentToolProvider.js";
25
- import { TurnContextBuilder } from "./agent/turn/TurnContextBuilder.js";
26
- import { TurnLifecycleService } from "./agent/turn/TurnLifecycleService.js";
27
- import { TurnPersistenceService } from "./agent/turn/TurnPersistenceService.js";
28
- import { TurnPromptBuilder } from "./agent/turn/TurnPromptBuilder.js";
29
- import { TurnStreamConsumer } from "./agent/turn/TurnStreamConsumer.js";
12
+ import { AdminForthCheckpointSaver } from "./persistence/checkpointStore.js";
13
+ import { appendCustomSystemPrompt, buildAgentSystemPrompt, DEFAULT_AGENT_SYSTEM_PROMPT } from "./domain/systemPrompt.js";
14
+ import { setupCoreEndpoints } from "./transport/http/coreEndpoints.js";
15
+ import { setupSessionEndpoints } from "./transport/http/sessionEndpoints.js";
16
+ import { setupChatSurfaceEndpoints } from "./transport/http/chatSurfaceEndpoints.js";
17
+ import { AgentSessionStore } from "./persistence/sessionStore.js";
18
+ import { ChatSurfaceService } from "./transport/surfaces/chatSurfaceService.js";
19
+ import { RunTurnUseCase } from "./application/runTurnUseCase.js";
20
+ import { createSequenceDebugCollector } from "./llm/middleware/sequenceDebug.js";
21
+ import { LangGraphLlm } from "./llm/langGraphLlm.js";
22
+ import { AgentModelFactory } from "./llm/modelFactory.js";
23
+ import { AgentRuntime } from "./llm/agentRuntime.js";
24
+ import { SpeechTurnService } from "./transport/surfaces/speechTurnService.js";
25
+ import { AgentToolProvider } from "./tools/agentToolProvider.js";
30
26
  export default class AdminForthAgentPlugin extends AdminForthPlugin {
31
27
  getCheckpointer() {
32
28
  if (this.checkpointer)
@@ -44,6 +40,18 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
44
40
  (_a = this.options.checkpointResource) === null || _a === void 0 ? void 0 : _a.resourceId,
45
41
  ].filter((resourceId) => Boolean(resourceId));
46
42
  }
43
+ getAgentSystemPrompt() {
44
+ return __awaiter(this, void 0, void 0, function* () {
45
+ if (!this.agentSystemPrompt) {
46
+ const systemPrompt = yield buildAgentSystemPrompt(this.adminforth, this.getInternalAgentResourceIds()).catch((err) => {
47
+ logger.error(`Failed to build agent system prompt, falling back to default: ${err instanceof Error ? err.message : String(err)}`);
48
+ return DEFAULT_AGENT_SYSTEM_PROMPT;
49
+ });
50
+ this.agentSystemPrompt = appendCustomSystemPrompt(systemPrompt, this.options.systemPrompt);
51
+ }
52
+ return this.agentSystemPrompt;
53
+ });
54
+ }
47
55
  constructor(options) {
48
56
  var _a;
49
57
  super(options, import.meta.url);
@@ -59,21 +67,18 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
59
67
  getCheckpointer: this.getCheckpointer.bind(this),
60
68
  toolProvider,
61
69
  });
62
- const persistence = new TurnPersistenceService(() => this.adminforth, this.options);
63
- this.agentTurnService = new AgentTurnService(new TurnLifecycleService(this.sessionStore, persistence, this.options), new TurnContextBuilder(() => this.adminforth), new AgentModeResolver(this.options), new AgentModelFactory((_a = this.options.maxTokens) !== null && _a !== void 0 ? _a : 1000), new TurnPromptBuilder({
70
+ const llm = new LangGraphLlm(runtime, new AgentModelFactory((_a = this.options.maxTokens) !== null && _a !== void 0 ? _a : 1000));
71
+ this.runTurnUseCase = new RunTurnUseCase({
72
+ llm,
73
+ sessions: this.sessionStore,
74
+ modes: this.options.modes,
64
75
  getAdminforth: () => this.adminforth,
65
- getAgentSystemPrompt: () => __awaiter(this, void 0, void 0, function* () {
66
- if (!this.agentSystemPrompt) {
67
- const systemPrompt = yield buildAgentSystemPrompt(this.adminforth, this.getInternalAgentResourceIds()).catch((err) => {
68
- return DEFAULT_AGENT_SYSTEM_PROMPT;
69
- });
70
- this.agentSystemPrompt = appendCustomSystemPrompt(systemPrompt, this.options.systemPrompt);
71
- }
72
- return this.agentSystemPrompt;
73
- }),
74
- }), runtime, new TurnStreamConsumer());
75
- this.speechTurnService = new SpeechTurnService(this.agentTurnService.runAndPersistAgentResponse.bind(this.agentTurnService));
76
- this.chatSurfaceService = new ChatSurfaceService(() => this.adminforth, this.options, this.sessionStore, this.agentTurnService.handleTurn.bind(this.agentTurnService), this.agentTurnService.runAndPersistAgentResponse.bind(this.agentTurnService));
76
+ getAgentSystemPrompt: this.getAgentSystemPrompt.bind(this),
77
+ hasPersistentCheckpointer: Boolean(this.options.checkpointResource),
78
+ createDebugSink: createSequenceDebugCollector,
79
+ });
80
+ this.speechTurnService = new SpeechTurnService(this.runTurnUseCase.runAndPersistAgentResponse.bind(this.runTurnUseCase));
81
+ this.chatSurfaceService = new ChatSurfaceService(() => this.adminforth, this.options, this.sessionStore, this.runTurnUseCase.handleTurn.bind(this.runTurnUseCase), this.runTurnUseCase.runAndPersistAgentResponse.bind(this.runTurnUseCase));
77
82
  this.agentSystemPromptPromise = Promise.resolve(appendCustomSystemPrompt(DEFAULT_AGENT_SYSTEM_PROMPT, this.options.systemPrompt));
78
83
  this.shouldHaveSingleInstancePerWholeApp = () => false;
79
84
  }
@@ -139,9 +144,9 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
139
144
  const endpointContext = {
140
145
  adminforth: this.adminforth,
141
146
  options: this.options,
142
- handleTurn: this.agentTurnService.handleTurn.bind(this.agentTurnService),
147
+ handleTurn: this.runTurnUseCase.handleTurn.bind(this.runTurnUseCase),
143
148
  handleSpeechTurn: this.speechTurnService.handle.bind(this.speechTurnService),
144
- runAndPersistAgentResponse: this.agentTurnService.runAndPersistAgentResponse.bind(this.agentTurnService),
149
+ runAndPersistAgentResponse: this.runTurnUseCase.runAndPersistAgentResponse.bind(this.runTurnUseCase),
145
150
  getSessionTurns: this.sessionStore.getSessionTurns.bind(this.sessionStore),
146
151
  createNewTurn: this.sessionStore.createNewTurn.bind(this.sessionStore),
147
152
  createSystemTurn: this.sessionStore.createSystemTurn.bind(this.sessionStore),
@@ -1,9 +1,9 @@
1
1
  import type { AdminUser } from "adminforth";
2
2
  import { z } from "zod";
3
- import type { AgentEventEmitter } from "../../agentEvents.js";
4
- import type { SequenceDebugCollector } from "../middleware/sequenceDebug.js";
3
+ import type { AgentEventEmitter } from "../domain/agentEvents.js";
4
+ import type { SequenceDebugCollector } from "./middleware/sequenceDebug.js";
5
5
  import type { CurrentPageContext } from "../tools/getUserLocation.js";
6
- import type { AgentTurnContext } from "../turn/turnTypes.js";
6
+ import type { AgentTurnContext } from "../domain/turnTypes.js";
7
7
  export declare const contextSchema: z.ZodObject<{
8
8
  adminUser: z.ZodCustom<AdminUser, AdminUser>;
9
9
  userTimeZone: z.ZodString;