@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
@@ -0,0 +1,117 @@
1
+ var __asyncValues = (this && this.__asyncValues) || function (o) {
2
+ if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
3
+ var m = o[Symbol.asyncIterator], i;
4
+ 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);
5
+ 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); }); }; }
6
+ function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
7
+ };
8
+ var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
9
+ var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
10
+ if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
11
+ var g = generator.apply(thisArg, _arguments || []), i, q = [];
12
+ return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
13
+ function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
14
+ function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
15
+ function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
16
+ function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
17
+ function fulfill(value) { resume("next", value); }
18
+ function reject(value) { resume("throw", value); }
19
+ function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
20
+ };
21
+ // Only tokens emitted by the model node(s) are surfaced to the user; other
22
+ // graph nodes (tools, summarization, etc.) are internal.
23
+ const STREAMABLE_NODES = ["model", "model_request"];
24
+ function getInterruptItems(interrupt) {
25
+ return Array.isArray(interrupt) ? interrupt : [interrupt];
26
+ }
27
+ /**
28
+ * Normalize raw LangGraph interrupt object(s) into provider-agnostic descriptors.
29
+ * Kept in the llm layer so the LangGraph interrupt shape never reaches the app.
30
+ */
31
+ export function normalizeInterrupts(interrupt) {
32
+ return getInterruptItems(interrupt).flatMap((item) => {
33
+ const value = item && typeof item === "object" && "value" in item
34
+ ? item.value
35
+ : item;
36
+ const actionRequests = value && typeof value === "object"
37
+ ? value.actionRequests
38
+ : undefined;
39
+ const interruptId = item && typeof item === "object"
40
+ ? item.id
41
+ : undefined;
42
+ return typeof interruptId === "string" && Array.isArray(actionRequests)
43
+ ? [{ id: interruptId, count: actionRequests.length }]
44
+ : [];
45
+ });
46
+ }
47
+ function extractBlocks(token) {
48
+ if (Array.isArray(token === null || token === void 0 ? void 0 : token.contentBlocks)) {
49
+ return token.contentBlocks;
50
+ }
51
+ if (Array.isArray(token === null || token === void 0 ? void 0 : token.content)) {
52
+ return token.content;
53
+ }
54
+ return [];
55
+ }
56
+ /**
57
+ * Convert one raw LangGraph stream entry into zero or more normalized chunks.
58
+ * Pure and synchronous so the parsing rules can be unit-tested in isolation.
59
+ */
60
+ export function parseRawStreamChunk(entry) {
61
+ const [mode, chunk] = entry;
62
+ if (mode === "updates") {
63
+ if (chunk && typeof chunk === "object" && "__interrupt__" in chunk) {
64
+ const interrupt = chunk.__interrupt__;
65
+ return [{ kind: "interrupt", interrupt, descriptors: normalizeInterrupts(interrupt) }];
66
+ }
67
+ return [];
68
+ }
69
+ const [token, metadata] = chunk;
70
+ const nodeName = typeof (metadata === null || metadata === void 0 ? void 0 : metadata.langgraph_node) === "string" ? metadata.langgraph_node : "";
71
+ if (nodeName && !STREAMABLE_NODES.includes(nodeName)) {
72
+ return [];
73
+ }
74
+ const blocks = extractBlocks(token);
75
+ const chunks = [];
76
+ const reasoning = blocks
77
+ .filter((block) => (block === null || block === void 0 ? void 0 : block.type) === "reasoning")
78
+ .map((block) => { var _a; return String((_a = block.reasoning) !== null && _a !== void 0 ? _a : ""); })
79
+ .join("");
80
+ const text = blocks
81
+ .filter((block) => (block === null || block === void 0 ? void 0 : block.type) === "text")
82
+ .map((block) => { var _a; return String((_a = block.text) !== null && _a !== void 0 ? _a : ""); })
83
+ .join("");
84
+ if (reasoning) {
85
+ chunks.push({ kind: "reasoning", delta: reasoning });
86
+ }
87
+ if (text) {
88
+ chunks.push({ kind: "text", delta: text });
89
+ }
90
+ return chunks;
91
+ }
92
+ /**
93
+ * Adapt the raw LangGraph `["messages" | "updates", ...]` stream into a typed
94
+ * `AgentStreamChunk` stream for the application layer.
95
+ */
96
+ export function adaptRawStream(raw) {
97
+ return __asyncGenerator(this, arguments, function* adaptRawStream_1() {
98
+ var _a, e_1, _b, _c;
99
+ try {
100
+ for (var _d = true, raw_1 = __asyncValues(raw), raw_1_1; raw_1_1 = yield __await(raw_1.next()), _a = raw_1_1.done, !_a; _d = true) {
101
+ _c = raw_1_1.value;
102
+ _d = false;
103
+ const entry = _c;
104
+ for (const chunk of parseRawStreamChunk(entry)) {
105
+ yield yield __await(chunk);
106
+ }
107
+ }
108
+ }
109
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
110
+ finally {
111
+ try {
112
+ if (!_d && !_a && (_b = raw_1.return)) yield __await(_b.call(raw_1));
113
+ }
114
+ finally { if (e_1) throw e_1.error; }
115
+ }
116
+ });
117
+ }
@@ -1,14 +1,21 @@
1
1
  import type { AdminUser, IAdminForth } from "adminforth";
2
2
  import type { ChatSurfaceIncomingMessage } from "adminforth";
3
- import type { PreviousUserMessage } from "./agent/languageDetect.js";
4
- import type { PluginOptions } from "./types.js";
3
+ import type { PreviousUserMessage } from "../domain/languageDetect.js";
4
+ import type { PluginOptions } from "../types.js";
5
5
  export declare const AGENT_SYSTEM_TURN_PROMPT = "__adminforth_system_message__";
6
+ export declare const STEER_PROMPT_MARKER = "__adminforth_steer__:";
6
7
  export declare class AgentSessionStore {
7
8
  private getAdminforth;
8
9
  private options;
9
10
  constructor(getAdminforth: () => IAdminForth, options: PluginOptions);
10
11
  createNewTurn(sessionId: string, prompt: string, response?: string): Promise<any>;
11
12
  createSystemTurn(sessionId: string, systemMessage: string): Promise<any>;
13
+ /**
14
+ * Append a mid-turn steer to the current (running) turn's prompt instead of creating a
15
+ * new record. Targets the latest non-system turn so a steer attaches to the real
16
+ * conversation turn, never an audio/system note.
17
+ */
18
+ appendSteerToCurrentTurn(sessionId: string, steerText: string): Promise<void>;
12
19
  getSessionTurns(sessionId: string): Promise<{
13
20
  prompt: any;
14
21
  response: any;
@@ -17,4 +24,14 @@ export declare class AgentSessionStore {
17
24
  getLatestTurn(sessionId: string): Promise<any>;
18
25
  getChatSurfaceSessionId(incoming: ChatSurfaceIncomingMessage): string;
19
26
  getOrCreateChatSurfaceSession(incoming: ChatSurfaceIncomingMessage, adminUser: AdminUser): Promise<string>;
27
+ touchSession(sessionId: string): Promise<void>;
28
+ saveTurnResponse(input: {
29
+ turnId: string;
30
+ responseText: string;
31
+ debugHistory?: unknown;
32
+ }): Promise<void>;
33
+ getResumeState(sessionId: string): Promise<{
34
+ turnId: string;
35
+ initialResponse: string;
36
+ }>;
20
37
  }
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  import { Filters, Sorts } from "adminforth";
11
11
  import { randomUUID } from "crypto";
12
12
  export const AGENT_SYSTEM_TURN_PROMPT = "__adminforth_system_message__";
13
+ export const STEER_PROMPT_MARKER = "__adminforth_steer__:";
13
14
  export class AgentSessionStore {
14
15
  constructor(getAdminforth, options) {
15
16
  this.getAdminforth = getAdminforth;
@@ -41,6 +42,25 @@ export class AgentSessionStore {
41
42
  return newTurn.createdRecord[this.options.turnResource.idField];
42
43
  });
43
44
  }
45
+ /**
46
+ * Append a mid-turn steer to the current (running) turn's prompt instead of creating a
47
+ * new record. Targets the latest non-system turn so a steer attaches to the real
48
+ * conversation turn, never an audio/system note.
49
+ */
50
+ appendSteerToCurrentTurn(sessionId, steerText) {
51
+ return __awaiter(this, void 0, void 0, function* () {
52
+ var _a;
53
+ const turns = yield this.getAdminforth().resource(this.options.turnResource.resourceId).list([Filters.EQ(this.options.turnResource.sessionIdField, sessionId)], undefined, undefined, [Sorts.DESC(this.options.turnResource.createdAtField)]);
54
+ const turn = turns.find((candidate) => candidate[this.options.turnResource.promptField] !== AGENT_SYSTEM_TURN_PROMPT);
55
+ if (!turn) {
56
+ return;
57
+ }
58
+ const currentPrompt = (_a = turn[this.options.turnResource.promptField]) !== null && _a !== void 0 ? _a : "";
59
+ yield this.getAdminforth().resource(this.options.turnResource.resourceId).update(turn[this.options.turnResource.idField], {
60
+ [this.options.turnResource.promptField]: `${currentPrompt}${STEER_PROMPT_MARKER}${steerText}`,
61
+ });
62
+ });
63
+ }
44
64
  getSessionTurns(sessionId) {
45
65
  return __awaiter(this, void 0, void 0, function* () {
46
66
  const turns = yield this.getAdminforth().resource(this.options.turnResource.resourceId).list([Filters.EQ(this.options.turnResource.sessionIdField, sessionId)], undefined, undefined, [Sorts.ASC(this.options.turnResource.createdAtField)]);
@@ -86,4 +106,37 @@ export class AgentSessionStore {
86
106
  return sessionId;
87
107
  });
88
108
  }
109
+ touchSession(sessionId) {
110
+ return __awaiter(this, void 0, void 0, function* () {
111
+ yield this.getAdminforth().resource(this.options.sessionResource.resourceId).update(sessionId, {
112
+ [this.options.sessionResource.createdAtField]: new Date().toISOString(),
113
+ });
114
+ });
115
+ }
116
+ saveTurnResponse(input) {
117
+ return __awaiter(this, void 0, void 0, function* () {
118
+ const turnUpdates = {
119
+ [this.options.turnResource.responseField]: input.responseText,
120
+ };
121
+ if (this.options.turnResource.debugField) {
122
+ turnUpdates[this.options.turnResource.debugField] = input.debugHistory;
123
+ }
124
+ yield this.getAdminforth()
125
+ .resource(this.options.turnResource.resourceId)
126
+ .update(input.turnId, turnUpdates);
127
+ });
128
+ }
129
+ getResumeState(sessionId) {
130
+ return __awaiter(this, void 0, void 0, function* () {
131
+ const latestTurn = yield this.getLatestTurn(sessionId);
132
+ if (!latestTurn) {
133
+ throw new Error(`No agent turn found for session "${sessionId}".`);
134
+ }
135
+ const response = latestTurn[this.options.turnResource.responseField];
136
+ return {
137
+ turnId: latestTurn[this.options.turnResource.idField],
138
+ initialResponse: response === "not_finished" ? "" : String(response),
139
+ };
140
+ });
141
+ }
89
142
  }
@@ -1,5 +1,5 @@
1
1
  import type { IAdminForth } from "adminforth";
2
- import type { ApiBasedTool } from "../../apiBasedTools.js";
2
+ import type { ApiBasedTool } from "./apiBasedTools.js";
3
3
  export declare class AgentToolProvider {
4
4
  private readonly getAdminforth;
5
5
  private readonly getInternalAgentResourceIds;
@@ -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 { prepareApiBasedTools } from "../../apiBasedTools.js";
10
+ import { prepareApiBasedTools } from "./apiBasedTools.js";
11
11
  import { createAgentTools } from "./index.js";
12
12
  export class AgentToolProvider {
13
13
  constructor(getAdminforth, getInternalAgentResourceIds) {
@@ -385,7 +385,6 @@ function callOpenApiSchema(params) {
385
385
  return validationErrorResponse('REQUEST_VALIDATION_FAILED', requestValidation.errors);
386
386
  }
387
387
  const response = createDirectToolResponse();
388
- logger.info(`Calling OpenAPI tool "${toolName}" with direct handler`);
389
388
  const lang = acceptLanguage !== null && acceptLanguage !== void 0 ? acceptLanguage : "en";
390
389
  const tr = (msg, category, trParams, pluralizationNumber) => adminforth.tr(msg, category, lang, trParams, pluralizationNumber);
391
390
  const output = yield withToolHandlerTimeout((handlerAbortSignal) => schema.handler({
@@ -449,8 +448,6 @@ export function prepareApiBasedTools(adminforth, hiddenResourceIds = []) {
449
448
  openApiSchemasByToolName.set(toolName, schema);
450
449
  }
451
450
  }
452
- logger.info(`AdminForth Agent OpenAPI APIs: ${formatLogNameList(adminforth.openApi.registeredSchemas.map((schema) => openApiSchemaPathToToolName(schema.path, adminforth)))}`);
453
- logger.info(`AdminForth Agent OpenAPI tools connected: ${formatLogNameList([...openApiSchemasByToolName.keys()])}`);
454
451
  for (const [toolName, schema] of openApiSchemasByToolName.entries()) {
455
452
  apiBasedTools[toolName] = {
456
453
  description: schema.description,
@@ -1,4 +1,4 @@
1
- import type { ApiBasedTool } from "../../apiBasedTools.js";
1
+ import type { ApiBasedTool } from "./apiBasedTools.js";
2
2
  export declare function createApiTool(toolName: string, apiBasedTool: ApiBasedTool): import("langchain").DynamicStructuredTool<Record<string, unknown> | {
3
3
  readonly type: "object";
4
4
  readonly properties: {};
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { tool } from "langchain";
11
11
  import { z } from "zod";
12
- import { listSkillManifests, loadSkillMarkdown, } from "../skills/registry.js";
12
+ import { listSkillManifests, loadSkillMarkdown, } from "./skills/registry.js";
13
13
  const fetchSkillSchema = z.object({
14
14
  skillName: z
15
15
  .string()
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import type { ApiBasedTool } from "../../apiBasedTools.js";
2
+ import type { ApiBasedTool } from "./apiBasedTools.js";
3
3
  export declare function createFetchToolSchemaTool(apiBasedTools: Record<string, ApiBasedTool>): Promise<import("langchain").DynamicStructuredTool<z.ZodObject<{
4
4
  toolName: z.ZodString;
5
5
  }, z.core.$strip>, {
@@ -1,4 +1,4 @@
1
1
  import type { ClientTool } from "@langchain/core/tools";
2
- import type { ApiBasedTool } from "../../apiBasedTools.js";
2
+ import type { ApiBasedTool } from "./apiBasedTools.js";
3
3
  export declare const ALWAYS_AVAILABLE_API_TOOL_NAMES: readonly ["get_resource"];
4
4
  export declare function createAgentTools(customComponentsDir: string, apiBasedTools: Record<string, ApiBasedTool>, pluginCustomFolderPaths?: string[]): Promise<ClientTool[]>;
@@ -17,8 +17,8 @@ export declare function createNavigateUserTool(): import("langchain").DynamicStr
17
17
  sort: z.ZodOptional<z.ZodObject<{
18
18
  column: z.ZodString;
19
19
  direction: z.ZodEnum<{
20
- asc: "asc";
21
20
  desc: "desc";
21
+ asc: "asc";
22
22
  }>;
23
23
  }, z.core.$strip>>;
24
24
  query: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
@@ -34,7 +34,7 @@ export declare function createNavigateUserTool(): import("langchain").DynamicStr
34
34
  }[] | undefined;
35
35
  sort?: {
36
36
  column: string;
37
- direction: "asc" | "desc";
37
+ direction: "desc" | "asc";
38
38
  } | undefined;
39
39
  query?: Record<string, string | number | boolean> | undefined;
40
40
  }, {
@@ -49,7 +49,7 @@ export declare function createNavigateUserTool(): import("langchain").DynamicStr
49
49
  }[] | undefined;
50
50
  sort?: {
51
51
  column: string;
52
- direction: "asc" | "desc";
52
+ direction: "desc" | "asc";
53
53
  } | undefined;
54
54
  query?: Record<string, string | number | boolean> | undefined;
55
55
  }, string, unknown, "navigate_user">;
@@ -1,6 +1,6 @@
1
1
  import type { ChatSurfaceAdapter, ChatSurfaceEventSink, ChatSurfaceIncomingMessage, IAdminForth } from "adminforth";
2
- import type { HandleSpeechTurnInput, HandleTurnInput, RunAndPersistAgentResponseInput, RunAndPersistAgentResponseResult } from "../agentTurnService.js";
3
- import type { PluginOptions } from "../types.js";
2
+ import type { HandleSpeechTurnInput, HandleTurnInput, RunAndPersistAgentResponseInput, RunAndPersistAgentResponseResult } from "../../domain/turnTypes.js";
3
+ import type { PluginOptions } from "../../types.js";
4
4
  export type SessionTurn = {
5
5
  prompt: string;
6
6
  response: string;
@@ -10,12 +10,20 @@ export type AgentEndpointsContext = {
10
10
  options: PluginOptions;
11
11
  handleTurn(input: HandleTurnInput): Promise<RunAndPersistAgentResponseResult>;
12
12
  handleSpeechTurn(input: HandleSpeechTurnInput): Promise<RunAndPersistAgentResponseResult | null>;
13
+ steer(input: {
14
+ sessionId: string;
15
+ message: string;
16
+ }): {
17
+ id: string;
18
+ queued: number;
19
+ };
13
20
  runAndPersistAgentResponse(input: RunAndPersistAgentResponseInput): Promise<RunAndPersistAgentResponseResult>;
14
21
  getSessionTurns(sessionId: string): Promise<SessionTurn[]>;
15
22
  createNewTurn(sessionId: string, prompt: string, response?: string): Promise<string>;
16
23
  createSystemTurn(sessionId: string, systemMessage: string): Promise<string>;
24
+ appendSteerToCurrentTurn(sessionId: string, steerText: string): Promise<void>;
17
25
  handleChatSurfaceMessage(adapter: ChatSurfaceAdapter, incoming: ChatSurfaceIncomingMessage, sink: ChatSurfaceEventSink): Promise<void>;
18
26
  };
19
- export type CoreEndpointsContext = Pick<AgentEndpointsContext, "options" | "handleTurn" | "handleSpeechTurn">;
20
- export type SessionEndpointsContext = Pick<AgentEndpointsContext, "adminforth" | "options" | "getSessionTurns" | "createNewTurn" | "createSystemTurn">;
27
+ export type CoreEndpointsContext = Pick<AgentEndpointsContext, "options" | "handleTurn" | "handleSpeechTurn" | "steer">;
28
+ export type SessionEndpointsContext = Pick<AgentEndpointsContext, "adminforth" | "options" | "getSessionTurns" | "createNewTurn" | "createSystemTurn" | "appendSteerToCurrentTurn">;
21
29
  export type ChatSurfaceEndpointsContext = Pick<AgentEndpointsContext, "adminforth" | "options" | "handleChatSurfaceMessage">;
@@ -0,0 +1 @@
1
+ export {};
@@ -8,7 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { z } from "zod";
11
- import { createSseEventEmitter } from "../surfaces/web-sse/createSseEventEmitter.js";
11
+ import { createSseEventEmitter } from "../sse/sseWriter.js";
12
12
  const currentPageContextSchema = z.object({
13
13
  path: z.string(),
14
14
  fullPath: z.string(),
@@ -26,6 +26,10 @@ const agentApprovalBodySchema = z.object({
26
26
  sessionId: z.string(),
27
27
  decision: z.enum(["approve", "reject"]),
28
28
  }).strict();
29
+ const agentSteerBodySchema = z.object({
30
+ sessionId: z.string(),
31
+ message: z.string().min(1),
32
+ }).strict();
29
33
  // Sent as multipart/form-data (via multer), so every field arrives as a plain string on the wire.
30
34
  // `currentPage` is JSON.stringify'd by the client into a form field and must be parsed back into
31
35
  // an object. Zod -> JSON-Schema conversion cannot represent `.transform()` at all (it throws), so
@@ -77,7 +81,7 @@ export function setupCoreEndpoints(ctx, server) {
77
81
  method: 'POST',
78
82
  path: `/agent/response`,
79
83
  request_schema: agentResponseBodySchema,
80
- handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response, _raw_express_res, abortSignal }) {
84
+ handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, _raw_express_res, abortSignal }) {
81
85
  var _b;
82
86
  const data = body;
83
87
  const emit = createSseEventEmitter(_raw_express_res, {
@@ -103,7 +107,7 @@ export function setupCoreEndpoints(ctx, server) {
103
107
  method: 'POST',
104
108
  path: `/agent/approval`,
105
109
  request_schema: agentApprovalBodySchema,
106
- handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response, _raw_express_res, abortSignal }) {
110
+ handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, _raw_express_res, abortSignal }) {
107
111
  const data = body;
108
112
  const emit = createSseEventEmitter(_raw_express_res, {
109
113
  vercelAiUiMessageStream: true,
@@ -122,6 +126,22 @@ export function setupCoreEndpoints(ctx, server) {
122
126
  return null;
123
127
  })
124
128
  });
129
+ server.endpoint({
130
+ method: 'POST',
131
+ path: `/agent/steer`,
132
+ request_schema: agentSteerBodySchema,
133
+ handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body }) {
134
+ const data = body;
135
+ // Fire-and-forget: the steer is buffered and folded into the running turn by the
136
+ // beforeModel steer middleware, which signals `data-steer-applied` on that turn's
137
+ // SSE stream once consumed. This endpoint only confirms it was received/queued.
138
+ const { id, queued } = ctx.steer({
139
+ sessionId: data.sessionId,
140
+ message: data.message,
141
+ });
142
+ return { ok: true, id, queued };
143
+ })
144
+ });
125
145
  server.endpoint({
126
146
  method: 'POST',
127
147
  path: `/agent/speech-response`,
@@ -10,11 +10,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  import { Filters, Sorts } from "adminforth";
11
11
  import { randomUUID } from "crypto";
12
12
  import { z } from "zod";
13
- import { AGENT_SYSTEM_TURN_PROMPT } from "../sessionStore.js";
13
+ import { AGENT_SYSTEM_TURN_PROMPT } from "../../persistence/sessionStore.js";
14
14
  const addSystemMessageBodySchema = z.object({
15
15
  sessionId: z.string(),
16
16
  systemMessage: z.string(),
17
17
  }).strict();
18
+ const appendSteerBodySchema = z.object({
19
+ sessionId: z.string(),
20
+ message: z.string().min(1),
21
+ }).strict();
18
22
  const getSessionsBodySchema = z.object({
19
23
  limit: z.number().int().min(1).max(100).optional(),
20
24
  }).strict();
@@ -54,11 +58,13 @@ export function setupSessionEndpoints(ctx, server) {
54
58
  const sessionId = data.sessionId;
55
59
  const session = yield ctx.adminforth.resource(ctx.options.sessionResource.resourceId).get([Filters.EQ(ctx.options.sessionResource.idField, sessionId)]);
56
60
  if (!session) {
61
+ response.setStatus(404, 'Session not found');
57
62
  return {
58
63
  error: 'Session not found'
59
64
  };
60
65
  }
61
66
  if (session[ctx.options.sessionResource.askerIdField] !== userId) {
67
+ response.setStatus(403, 'Unauthorized');
62
68
  return {
63
69
  error: 'Unauthorized'
64
70
  };
@@ -129,11 +135,13 @@ export function setupSessionEndpoints(ctx, server) {
129
135
  const userId = adminUser.pk;
130
136
  const session = yield ctx.adminforth.resource(ctx.options.sessionResource.resourceId).get([Filters.EQ(ctx.options.sessionResource.idField, sessionId)]);
131
137
  if (!session) {
138
+ response.setStatus(404, 'Session not found');
132
139
  return {
133
140
  error: 'Session not found'
134
141
  };
135
142
  }
136
143
  if (session[ctx.options.sessionResource.askerIdField] !== userId) {
144
+ response.setStatus(403, 'Unauthorized');
137
145
  return {
138
146
  error: 'Unauthorized'
139
147
  };
@@ -154,11 +162,13 @@ export function setupSessionEndpoints(ctx, server) {
154
162
  const data = body;
155
163
  const session = yield ctx.adminforth.resource(ctx.options.sessionResource.resourceId).get([Filters.EQ(ctx.options.sessionResource.idField, data.sessionId)]);
156
164
  if (!session) {
165
+ response.setStatus(404, 'Session not found');
157
166
  return {
158
167
  error: 'Session not found'
159
168
  };
160
169
  }
161
170
  if (session[ctx.options.sessionResource.askerIdField] !== adminUser.pk) {
171
+ response.setStatus(403, 'Unauthorized');
162
172
  return {
163
173
  error: 'Unauthorized'
164
174
  };
@@ -169,4 +179,29 @@ export function setupSessionEndpoints(ctx, server) {
169
179
  };
170
180
  })
171
181
  });
182
+ server.endpoint({
183
+ method: 'POST',
184
+ path: `/agent/append-steer-to-turn`,
185
+ request_schema: appendSteerBodySchema,
186
+ handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response }) {
187
+ const data = body;
188
+ const session = yield ctx.adminforth.resource(ctx.options.sessionResource.resourceId).get([Filters.EQ(ctx.options.sessionResource.idField, data.sessionId)]);
189
+ if (!session) {
190
+ response.setStatus(404, 'Session not found');
191
+ return {
192
+ error: 'Session not found'
193
+ };
194
+ }
195
+ if (session[ctx.options.sessionResource.askerIdField] !== adminUser.pk) {
196
+ response.setStatus(403, 'Unauthorized');
197
+ return {
198
+ error: 'Unauthorized'
199
+ };
200
+ }
201
+ yield ctx.appendSteerToCurrentTurn(data.sessionId, data.message);
202
+ return {
203
+ ok: true
204
+ };
205
+ })
206
+ });
172
207
  }
@@ -0,0 +1,29 @@
1
+ import type { AgentEventEmitter } from "../../domain/agentEvents.js";
2
+ type AgentEventStreamResponse = {
3
+ writeHead: (statusCode: number, headers: Record<string, string>) => void;
4
+ write: (chunk: string) => unknown;
5
+ end: () => unknown;
6
+ writableEnded: boolean;
7
+ destroyed: boolean;
8
+ };
9
+ type AgentEventStreamOptions = {
10
+ vercelAiUiMessageStream?: boolean;
11
+ closeActiveBlockOnToolStart?: boolean;
12
+ };
13
+ /**
14
+ * Maps the internal {@link AgentEvent} vocabulary onto the two Server-Sent-Events
15
+ * wire dialects the frontend consumes. Both dialects are HARD external contracts —
16
+ * do not change frame names/shapes without updating the corresponding consumer:
17
+ *
18
+ * - `vercelAiUiMessageStream: true` (used by `/agent/response` and `/agent/approval`):
19
+ * the Vercel AI SDK message-stream v1 format (`start`, `text-start`/`text-delta`/
20
+ * `text-end`, `reasoning-*`, `data-*` parts including `data-steer-applied`,
21
+ * `error` with `errorText`, `finish`, `[DONE]`). Consumed by `DefaultChatTransport`
22
+ * and the manual approval parser in `custom/composables/agentStore/useAgentChat.ts`.
23
+ * - default (used by `/agent/speech-response`): bare event names
24
+ * (`transcript`, `speech-response`, `audio-start`/`audio-delta`/`audio-done`,
25
+ * `open-page`, `error`) plus the Vercel-shaped `data-tool-call`. Consumed by
26
+ * `custom/composables/useAgentAudio.ts`.
27
+ */
28
+ export declare function createSseEventEmitter(res: AgentEventStreamResponse, options?: AgentEventStreamOptions): AgentEventEmitter;
29
+ export {};
@@ -98,6 +98,15 @@ function createAgentEventStream(res, options = {}) {
98
98
  },
99
99
  });
100
100
  },
101
+ steerApplied(count, ids) {
102
+ stream.send({
103
+ type: isAiUiMessageStream ? "data-steer-applied" : "steer-applied",
104
+ data: {
105
+ count,
106
+ ids,
107
+ },
108
+ });
109
+ },
101
110
  openPage(targetPath) {
102
111
  stream.send({
103
112
  type: isAiUiMessageStream ? "data-open-page" : "open-page",
@@ -185,6 +194,21 @@ function createAgentEventStream(res, options = {}) {
185
194
  };
186
195
  return stream;
187
196
  }
197
+ /**
198
+ * Maps the internal {@link AgentEvent} vocabulary onto the two Server-Sent-Events
199
+ * wire dialects the frontend consumes. Both dialects are HARD external contracts —
200
+ * do not change frame names/shapes without updating the corresponding consumer:
201
+ *
202
+ * - `vercelAiUiMessageStream: true` (used by `/agent/response` and `/agent/approval`):
203
+ * the Vercel AI SDK message-stream v1 format (`start`, `text-start`/`text-delta`/
204
+ * `text-end`, `reasoning-*`, `data-*` parts including `data-steer-applied`,
205
+ * `error` with `errorText`, `finish`, `[DONE]`). Consumed by `DefaultChatTransport`
206
+ * and the manual approval parser in `custom/composables/agentStore/useAgentChat.ts`.
207
+ * - default (used by `/agent/speech-response`): bare event names
208
+ * (`transcript`, `speech-response`, `audio-start`/`audio-delta`/`audio-done`,
209
+ * `open-page`, `error`) plus the Vercel-shaped `data-tool-call`. Consumed by
210
+ * `custom/composables/useAgentAudio.ts`.
211
+ */
188
212
  export function createSseEventEmitter(res, options = {}) {
189
213
  const stream = createAgentEventStream(res, options);
190
214
  return (event) => __awaiter(this, void 0, void 0, function* () {
@@ -207,6 +231,9 @@ export function createSseEventEmitter(res, options = {}) {
207
231
  case "interrupt":
208
232
  stream.interrupt(event.sessionId, event.interrupt);
209
233
  break;
234
+ case "steer-applied":
235
+ stream.steerApplied(event.count, event.ids);
236
+ break;
210
237
  case "open-page":
211
238
  stream.openPage(event.targetPath);
212
239
  break;
@@ -1,7 +1,7 @@
1
1
  import type { ChatSurfaceAdapter, ChatSurfaceEventSink, ChatSurfaceIncomingMessage, IAdminForth } from "adminforth";
2
- import type { HandleTurnInput, RunAndPersistAgentResponseInput, RunAndPersistAgentResponseResult } from "./agentTurnService.js";
3
- import type { AgentSessionStore } from "./sessionStore.js";
4
- import type { PluginOptions } from "./types.js";
2
+ import type { HandleTurnInput, RunAndPersistAgentResponseInput, RunAndPersistAgentResponseResult } from "../../domain/turnTypes.js";
3
+ import type { AgentSessionStore } from "../../persistence/sessionStore.js";
4
+ import type { PluginOptions } from "../../types.js";
5
5
  export declare class ChatSurfaceService {
6
6
  private getAdminforth;
7
7
  private options;
@@ -8,8 +8,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { Filters, logger } from "adminforth";
11
- import { getErrorMessage, isAbortError } from "./errors.js";
12
- import { sanitizeSpeechText } from "./sanitizeSpeechText.js";
11
+ import { getErrorMessage, isAbortError } from "../../shared/errors.js";
12
+ import { sanitizeSpeechText } from "../../shared/sanitizeSpeechText.js";
13
13
  export class ChatSurfaceService {
14
14
  constructor(getAdminforth, options, sessionStore, handleTurn, runAndPersistAgentResponse) {
15
15
  this.getAdminforth = getAdminforth;
@@ -35,9 +35,11 @@ export class ChatSurfaceService {
35
35
  return;
36
36
  }
37
37
  if (event.type === "error") {
38
+ // Full error detail is logged server-side (see runAndPersistAgentResponse);
39
+ // external chat users receive a generic message to avoid leaking internals.
38
40
  yield sink.emit({
39
41
  type: "error",
40
- message: event.error,
42
+ message: "Agent response failed. Check server logs for details.",
41
43
  });
42
44
  }
43
45
  });
@@ -122,7 +124,7 @@ export class ChatSurfaceService {
122
124
  logger.error(`Agent ${incoming.surface} surface speech synthesis failed:\n${getErrorMessage(error)}`);
123
125
  yield sink.emit({
124
126
  type: "error",
125
- message: getErrorMessage(error),
127
+ message: "Speech synthesis failed. Check server logs for details.",
126
128
  });
127
129
  }
128
130
  });
@@ -165,7 +167,7 @@ export class ChatSurfaceService {
165
167
  if (agentResponse.failed) {
166
168
  yield sink.emit({
167
169
  type: "error",
168
- message: agentResponse.text,
170
+ message: "Agent response failed. Check server logs for details.",
169
171
  });
170
172
  }
171
173
  return agentResponse;
@@ -1,4 +1,4 @@
1
- import type { RunAndPersistAgentResponseInput, RunAndPersistAgentResponseResult, SpeechAgentTurnInput } from "../turn/turnTypes.js";
1
+ import type { RunAndPersistAgentResponseInput, RunAndPersistAgentResponseResult, SpeechAgentTurnInput } from "../../domain/turnTypes.js";
2
2
  export declare class SpeechTurnService {
3
3
  private readonly runAndPersistAgentResponse;
4
4
  constructor(runAndPersistAgentResponse: (input: RunAndPersistAgentResponseInput) => Promise<RunAndPersistAgentResponseResult>);