@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
@@ -2,22 +2,26 @@ import type { BaseChatModel } from "@langchain/core/language_models/chat_models"
2
2
  import { type CompletionAdapter } from "adminforth";
3
3
  import { BaseCallbackHandler } from "@langchain/core/callbacks/base";
4
4
  import type { LLMResult } from "@langchain/core/outputs";
5
+ import type { Messages, Command } from "@langchain/langgraph";
5
6
  import { createSequenceDebugMiddleware } from "./middleware/sequenceDebug.js";
7
+ import type { AgentModelPurpose } from "../application/ports.js";
8
+ import type { AgentTurnContext, AgentTurnObservability } from "../domain/turnTypes.js";
9
+ export type { AgentModeCompletionAdapter, AgentModelPurpose } from "../application/ports.js";
6
10
  export type AgentChatModel = BaseChatModel<any, any>;
7
- export type AgentModelPurpose = "primary" | "summary";
8
- export type AgentModeCompletionAdapter = CompletionAdapter & {
9
- getLangChainAgentSpec(params: {
10
- maxTokens: number;
11
- purpose: AgentModelPurpose;
12
- }): Promise<{
13
- model: unknown;
14
- middleware?: unknown[];
15
- }> | {
16
- model: unknown;
17
- middleware?: unknown[];
18
- };
19
- };
20
11
  export type AgentMiddleware = ReturnType<typeof createSequenceDebugMiddleware>;
12
+ export type AgentTurnModels = {
13
+ model: AgentChatModel;
14
+ summaryModel: AgentChatModel;
15
+ modelMiddleware?: AgentMiddleware[];
16
+ };
17
+ export type AgentRuntimeRunInput = {
18
+ models: AgentTurnModels;
19
+ input: {
20
+ messages: Messages;
21
+ } | Command;
22
+ context: AgentTurnContext;
23
+ observability: AgentTurnObservability;
24
+ };
21
25
  type AgentChatModelSpec = {
22
26
  model: AgentChatModel;
23
27
  middleware: AgentMiddleware[];
@@ -27,8 +31,7 @@ declare class AgentLlmMetricsLogger extends BaseCallbackHandler {
27
31
  lc_prefer_streaming: boolean;
28
32
  private readonly pendingRuns;
29
33
  handleLLMStart(_llm: unknown, _prompts: string[], runId: string): Promise<void>;
30
- handleLLMNewToken(_token: string, _chunk: unknown, runId: string): Promise<void>;
31
- handleLLMEnd(output: LLMResult, runId: string): Promise<void>;
34
+ handleLLMEnd(_output: LLMResult, runId: string): Promise<void>;
32
35
  handleLLMError(_error: unknown, runId: string): Promise<void>;
33
36
  }
34
37
  export declare function createAgentLlmMetricsLogger(): AgentLlmMetricsLogger;
@@ -37,4 +40,3 @@ export declare function createAgentChatModel(params: {
37
40
  maxTokens: number;
38
41
  purpose: AgentModelPurpose;
39
42
  }): Promise<AgentChatModelSpec>;
40
- export {};
@@ -0,0 +1,65 @@
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
+ import { BaseCallbackHandler } from "@langchain/core/callbacks/base";
11
+ function isLangChainAgentCompletionAdapter(adapter) {
12
+ return typeof adapter
13
+ .getLangChainAgentSpec === "function";
14
+ }
15
+ function getAgentChatModelSpec(params) {
16
+ return __awaiter(this, void 0, void 0, function* () {
17
+ var _a;
18
+ const spec = yield params.adapter.getLangChainAgentSpec({
19
+ maxTokens: params.maxTokens,
20
+ purpose: params.purpose,
21
+ });
22
+ return {
23
+ model: spec.model,
24
+ middleware: ((_a = spec.middleware) !== null && _a !== void 0 ? _a : []),
25
+ };
26
+ });
27
+ }
28
+ class AgentLlmMetricsLogger extends BaseCallbackHandler {
29
+ constructor() {
30
+ super(...arguments);
31
+ this.name = "AgentLlmMetricsLogger";
32
+ this.lc_prefer_streaming = true;
33
+ this.pendingRuns = new Map();
34
+ }
35
+ handleLLMStart(_llm, _prompts, runId) {
36
+ return __awaiter(this, void 0, void 0, function* () {
37
+ this.pendingRuns.set(runId, { startedAt: Date.now() });
38
+ });
39
+ }
40
+ handleLLMEnd(_output, runId) {
41
+ return __awaiter(this, void 0, void 0, function* () {
42
+ this.pendingRuns.delete(runId);
43
+ });
44
+ }
45
+ handleLLMError(_error, runId) {
46
+ return __awaiter(this, void 0, void 0, function* () {
47
+ this.pendingRuns.delete(runId);
48
+ });
49
+ }
50
+ }
51
+ export function createAgentLlmMetricsLogger() {
52
+ return new AgentLlmMetricsLogger();
53
+ }
54
+ export function createAgentChatModel(params) {
55
+ return __awaiter(this, void 0, void 0, function* () {
56
+ if (!isLangChainAgentCompletionAdapter(params.adapter)) {
57
+ throw new Error("AdminForth Agent requires completionAdapter to implement getLangChainAgentSpec({ maxTokens, purpose }).");
58
+ }
59
+ return yield getAgentChatModelSpec({
60
+ adapter: params.adapter,
61
+ maxTokens: params.maxTokens,
62
+ purpose: params.purpose,
63
+ });
64
+ });
65
+ }
@@ -1,7 +1,7 @@
1
1
  import type { IAdminForth } from "adminforth";
2
2
  import type { BaseCheckpointSaver } from "@langchain/langgraph";
3
- import type { AgentToolProvider } from "../tools/AgentToolProvider.js";
4
- import type { AgentRuntimeRunInput } from "../turn/turnTypes.js";
3
+ import type { AgentToolProvider } from "../tools/agentToolProvider.js";
4
+ import type { AgentRuntimeRunInput, AgentTurnModels } from "./agentModels.js";
5
5
  export type AgentRuntimeOptions = {
6
6
  name: string;
7
7
  getAdminforth: () => IAdminForth;
@@ -12,4 +12,13 @@ export declare class AgentRuntime {
12
12
  private readonly options;
13
13
  constructor(options: AgentRuntimeOptions);
14
14
  stream(input: AgentRuntimeRunInput): Promise<import("@langchain/core/utils/stream").IterableReadableStream<["messages", [import("langchain").BaseMessage<import("@langchain/core/messages").MessageStructure<import("@langchain/core/messages").MessageToolSet>, import("@langchain/core/messages").MessageType>, Record<string, any>]] | ["updates", Record<string, Omit<import("langchain").BuiltInState<import("@langchain/core/messages").MessageStructure<import("langchain").ToolsToMessageToolSet<readonly (import("@langchain/core/tools").ClientTool | import("@langchain/core/tools").ServerTool)[]>>>, "jumpTo">>]>>;
15
+ /**
16
+ * Read the pending human-in-the-loop interrupts persisted for a thread from the
17
+ * checkpointer. Builds a minimal agent (model + checkpointer + HITL middleware) and
18
+ * queries its state — no model call is made. Returns raw LangGraph interrupt objects.
19
+ */
20
+ getPendingInterrupts(input: {
21
+ models: AgentTurnModels;
22
+ sessionId: string;
23
+ }): Promise<unknown[]>;
15
24
  }
@@ -8,10 +8,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { createAgent, summarizationMiddleware, humanInTheLoopMiddleware } from "langchain";
11
- import { createApiBasedToolsMiddleware } from "../middleware/apiBasedTools.js";
12
- import { createSequenceDebugMiddleware } from "../middleware/sequenceDebug.js";
13
- import { createAgentLlmMetricsLogger } from "../simpleAgent.js";
14
- import { contextSchema, toLangchainAgentContext } from "./AgentContext.js";
11
+ import { createApiBasedToolsMiddleware } from "./middleware/apiToolsMiddleware.js";
12
+ import { createSequenceDebugMiddleware } from "./middleware/sequenceDebug.js";
13
+ import { createAgentLlmMetricsLogger } from "./agentModels.js";
14
+ import { contextSchema, toLangchainAgentContext } from "./agentContext.js";
15
15
  function createHumanInTheLoopInterrupts(apiBasedTools) {
16
16
  return Object.fromEntries(Object.entries(apiBasedTools)
17
17
  .filter(([, apiBasedTool]) => { var _a; return ((_a = apiBasedTool.agent) === null || _a === void 0 ? void 0 : _a.isDangerous) === true; })
@@ -33,7 +33,10 @@ export class AgentRuntime {
33
33
  const tools = yield this.options.toolProvider.getTools(apiBasedTools);
34
34
  const adminforth = this.options.getAdminforth();
35
35
  const apiBasedToolsMiddleware = createApiBasedToolsMiddleware(apiBasedTools, adminforth);
36
- const sequenceDebugMiddleware = createSequenceDebugMiddleware(input.observability.sequenceDebugSink);
36
+ // The domain exposes only the narrow DebugSink; the concrete collector (with the
37
+ // model-call hooks the debug middleware needs) is an llm-layer detail.
38
+ const sequenceDebugSink = input.observability.sequenceDebugSink;
39
+ const sequenceDebugMiddleware = createSequenceDebugMiddleware(sequenceDebugSink);
37
40
  const hitlMiddleware = humanInTheLoopMiddleware({
38
41
  interruptOn: createHumanInTheLoopInterrupts(apiBasedTools),
39
42
  descriptionPrefix: "Tool execution pending approval",
@@ -65,8 +68,37 @@ export class AgentRuntime {
65
68
  configurable: {
66
69
  thread_id: input.context.sessionId,
67
70
  },
68
- context: toLangchainAgentContext(Object.assign(Object.assign({}, input.context), { adminBaseUrl: adminforth.config.baseUrlSlashed, emit: input.observability.emit, sequenceDebugSink: input.observability.sequenceDebugSink })),
71
+ context: toLangchainAgentContext(Object.assign(Object.assign({}, input.context), { adminBaseUrl: adminforth.config.baseUrlSlashed, emit: input.observability.emit, sequenceDebugSink })),
69
72
  });
70
73
  });
71
74
  }
75
+ /**
76
+ * Read the pending human-in-the-loop interrupts persisted for a thread from the
77
+ * checkpointer. Builds a minimal agent (model + checkpointer + HITL middleware) and
78
+ * queries its state — no model call is made. Returns raw LangGraph interrupt objects.
79
+ */
80
+ getPendingInterrupts(input) {
81
+ return __awaiter(this, void 0, void 0, function* () {
82
+ const apiBasedTools = this.options.toolProvider.getApiBasedTools();
83
+ const tools = yield this.options.toolProvider.getTools(apiBasedTools);
84
+ const agent = createAgent({
85
+ name: this.options.name,
86
+ model: input.models.model,
87
+ checkpointer: this.options.getCheckpointer(),
88
+ tools,
89
+ contextSchema,
90
+ middleware: [
91
+ humanInTheLoopMiddleware({
92
+ interruptOn: createHumanInTheLoopInterrupts(apiBasedTools),
93
+ descriptionPrefix: "Tool execution pending approval",
94
+ }),
95
+ ],
96
+ });
97
+ const state = yield agent.getState({
98
+ configurable: { thread_id: input.sessionId },
99
+ });
100
+ const tasks = Array.isArray(state === null || state === void 0 ? void 0 : state.tasks) ? state.tasks : [];
101
+ return tasks.flatMap((task) => (Array.isArray(task === null || task === void 0 ? void 0 : task.interrupts) ? task.interrupts : []));
102
+ });
103
+ }
72
104
  }
@@ -0,0 +1,25 @@
1
+ import type { AgentRuntime } from "./agentRuntime.js";
2
+ import type { AgentModelFactory } from "./modelFactory.js";
3
+ import { type PreviousUserMessage } from "../domain/languageDetect.js";
4
+ import type { AgentModeCompletionAdapter, LlmPort, LlmStreamInput } from "../application/ports.js";
5
+ import type { PendingInterrupt } from "../domain/turnTypes.js";
6
+ /**
7
+ * LangChain/LangGraph implementation of {@link LlmPort}. This is the single
8
+ * place that knows about the agent graph, model construction, and the raw
9
+ * stream shape; the application layer talks only to the port.
10
+ */
11
+ export declare class LangGraphLlm implements LlmPort {
12
+ private readonly runtime;
13
+ private readonly modelFactory;
14
+ constructor(runtime: AgentRuntime, modelFactory: AgentModelFactory);
15
+ streamTurn(input: LlmStreamInput): Promise<AsyncGenerator<import("../domain/turnTypes.js").AgentStreamChunk, any, any>>;
16
+ detectLanguage(input: {
17
+ completionAdapter: AgentModeCompletionAdapter;
18
+ prompt: string;
19
+ previousUserMessages: PreviousUserMessage[];
20
+ }): Promise<import("../domain/languageDetect.js").DetectedLanguage | null>;
21
+ getPendingInterrupts(input: {
22
+ completionAdapter: AgentModeCompletionAdapter;
23
+ sessionId: string;
24
+ }): Promise<PendingInterrupt[]>;
25
+ }
@@ -0,0 +1,54 @@
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
+ import { Command } from "@langchain/langgraph";
11
+ import { HumanMessage, SystemMessage } from "langchain";
12
+ import { detectUserLanguage } from "../domain/languageDetect.js";
13
+ import { adaptRawStream, normalizeInterrupts } from "./streamAdapter.js";
14
+ function toLangchainMessages(messages) {
15
+ return messages.map((message) => message.role === "system"
16
+ ? new SystemMessage(message.content)
17
+ : new HumanMessage(message.content));
18
+ }
19
+ /**
20
+ * LangChain/LangGraph implementation of {@link LlmPort}. This is the single
21
+ * place that knows about the agent graph, model construction, and the raw
22
+ * stream shape; the application layer talks only to the port.
23
+ */
24
+ export class LangGraphLlm {
25
+ constructor(runtime, modelFactory) {
26
+ this.runtime = runtime;
27
+ this.modelFactory = modelFactory;
28
+ }
29
+ streamTurn(input) {
30
+ return __awaiter(this, void 0, void 0, function* () {
31
+ const models = yield this.modelFactory.create(input.completionAdapter);
32
+ const runtimeInput = "resume" in input.input
33
+ ? new Command({ resume: input.input.resume })
34
+ : { messages: toLangchainMessages(input.input.messages) };
35
+ const rawStream = yield this.runtime.stream({
36
+ models,
37
+ input: runtimeInput,
38
+ context: input.context,
39
+ observability: input.observability,
40
+ });
41
+ return adaptRawStream(rawStream);
42
+ });
43
+ }
44
+ detectLanguage(input) {
45
+ return detectUserLanguage(input.completionAdapter, input.prompt, input.previousUserMessages);
46
+ }
47
+ getPendingInterrupts(input) {
48
+ return __awaiter(this, void 0, void 0, function* () {
49
+ const models = yield this.modelFactory.create(input.completionAdapter);
50
+ const raw = yield this.runtime.getPendingInterrupts({ models, sessionId: input.sessionId });
51
+ return normalizeInterrupts(raw);
52
+ });
53
+ }
54
+ }
@@ -1,3 +1,3 @@
1
1
  import { type IAdminForth } from "adminforth";
2
- import { type ApiBasedTool } from "../../apiBasedTools.js";
2
+ import { type ApiBasedTool } from "../../tools/apiBasedTools.js";
3
3
  export declare function createApiBasedToolsMiddleware(apiBasedTools: Record<string, ApiBasedTool>, adminforth: IAdminForth): import("langchain").AgentMiddleware<undefined, undefined, unknown, readonly (import("@langchain/core/tools").ClientTool | import("@langchain/core/tools").ServerTool)[]>;
@@ -11,11 +11,11 @@ import { ToolMessage } from "@langchain/core/messages";
11
11
  import { isGraphInterrupt } from "@langchain/langgraph";
12
12
  import { createMiddleware } from "langchain";
13
13
  import { logger } from "adminforth";
14
- import { formatApiBasedToolCall, } from "../../apiBasedTools.js";
15
- import { createToolCallTracker, } from "../toolCallEvents.js";
16
- import { ALWAYS_AVAILABLE_API_TOOL_NAMES } from "../tools/index.js";
17
- import { createApiTool } from "../tools/apiTool.js";
18
- import { isAbortError } from "../../errors.js";
14
+ import { formatApiBasedToolCall, } from "../../tools/apiBasedTools.js";
15
+ import { createToolCallTracker, } from "../../domain/toolCallEvents.js";
16
+ import { ALWAYS_AVAILABLE_API_TOOL_NAMES } from "../../tools/index.js";
17
+ import { createApiTool } from "../../tools/apiTool.js";
18
+ import { isAbortError } from "../../shared/errors.js";
19
19
  function getEnabledApiToolNames(messages) {
20
20
  const enabledToolNames = new Set();
21
21
  for (const message of messages) {
@@ -58,15 +58,13 @@ export function createApiBasedToolsMiddleware(apiBasedTools, adminforth) {
58
58
  .filter((toolName) => !alwaysAvailableApiToolNames.has(toolName))
59
59
  .map((toolName) => dynamicTools[toolName]);
60
60
  const availableTools = [...request.tools, ...tools];
61
- logger.info(`AdminForth Agent callable tools: ${availableTools.map((tool) => tool.name).join(", ")}`);
62
61
  return handler(Object.assign(Object.assign({}, request), { tools: availableTools }));
63
62
  });
64
63
  },
65
64
  wrapToolCall(request, handler) {
66
65
  return __awaiter(this, void 0, void 0, function* () {
67
- var _a, _b, _c;
66
+ var _a, _b;
68
67
  const startedAt = Date.now();
69
- const toolInput = JSON.stringify((_a = request.toolCall.args) !== null && _a !== void 0 ? _a : {});
70
68
  if (!request.toolCall.id) {
71
69
  throw new Error(`Tool call "${request.toolCall.name}" has no id.`);
72
70
  }
@@ -79,7 +77,7 @@ export function createApiBasedToolsMiddleware(apiBasedTools, adminforth) {
79
77
  data: event,
80
78
  }));
81
79
  };
82
- const toolArgs = ((_b = request.toolCall.args) !== null && _b !== void 0 ? _b : {});
80
+ const toolArgs = ((_a = request.toolCall.args) !== null && _a !== void 0 ? _a : {});
83
81
  let toolInfo;
84
82
  if (request.toolCall.name === "fetch_skill") {
85
83
  toolInfo = `Load ${toolArgs.skillName.split("_").join(" ")} skill`;
@@ -105,7 +103,6 @@ export function createApiBasedToolsMiddleware(apiBasedTools, adminforth) {
105
103
  startedAt,
106
104
  });
107
105
  toolCallTracker.start();
108
- logger.info(`Invoking tool "${request.toolCall.name}" with input: ${toolInput}`);
109
106
  try {
110
107
  const result = getEnabledApiToolNames(request.state.messages).has(request.toolCall.name)
111
108
  ? yield handler(Object.assign(Object.assign({}, request), { tool: dynamicTools[request.toolCall.name] }))
@@ -120,7 +117,7 @@ export function createApiBasedToolsMiddleware(apiBasedTools, adminforth) {
120
117
  throw error;
121
118
  }
122
119
  const message = error instanceof Error ? error.message : String(error);
123
- logger.error(`Error calling tool "${request.toolCall.name}": ${error instanceof Error ? (_c = error.stack) !== null && _c !== void 0 ? _c : error.message : String(error)}`);
120
+ logger.error(`Error calling tool "${request.toolCall.name}": ${error instanceof Error ? (_b = error.stack) !== null && _b !== void 0 ? _b : error.message : String(error)}`);
124
121
  toolCallTracker.finishError(`Error: ${message}`);
125
122
  return new ToolMessage({
126
123
  name: request.toolCall.name,
@@ -129,9 +126,6 @@ export function createApiBasedToolsMiddleware(apiBasedTools, adminforth) {
129
126
  content: `Error: ${message}`,
130
127
  });
131
128
  }
132
- finally {
133
- logger.info(`Tool "${request.toolCall.name}" finished in ${Date.now() - startedAt}ms`);
134
- }
135
129
  });
136
130
  },
137
131
  });
@@ -1,4 +1,4 @@
1
- import type { ToolCallEvent } from "../toolCallEvents.js";
1
+ import type { ToolCallEvent } from "../../domain/toolCallEvents.js";
2
2
  export type SequenceDebugResultType = "tool_calls" | "final_text";
3
3
  type SequenceDebugToolCall = {
4
4
  toolCallId: string;
@@ -1,5 +1,5 @@
1
1
  import type { CompletionAdapter } from "adminforth";
2
- import type { AgentTurnModels } from "../turn/turnTypes.js";
2
+ import { type AgentTurnModels } from "./agentModels.js";
3
3
  export declare class AgentModelFactory {
4
4
  private readonly maxTokens;
5
5
  constructor(maxTokens: number);
@@ -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 { createAgentChatModel } from "../simpleAgent.js";
10
+ import { createAgentChatModel } from "./agentModels.js";
11
11
  export class AgentModelFactory {
12
12
  constructor(maxTokens) {
13
13
  this.maxTokens = maxTokens;
@@ -0,0 +1,18 @@
1
+ import type { AgentStreamChunk, PendingInterrupt } from "../domain/turnTypes.js";
2
+ /**
3
+ * Normalize raw LangGraph interrupt object(s) into provider-agnostic descriptors.
4
+ * Kept in the llm layer so the LangGraph interrupt shape never reaches the app.
5
+ */
6
+ export declare function normalizeInterrupts(interrupt: unknown): PendingInterrupt[];
7
+ type RawStreamEntry = ["messages", [any, any]] | ["updates", Record<string, any>];
8
+ /**
9
+ * Convert one raw LangGraph stream entry into zero or more normalized chunks.
10
+ * Pure and synchronous so the parsing rules can be unit-tested in isolation.
11
+ */
12
+ export declare function parseRawStreamChunk(entry: RawStreamEntry): AgentStreamChunk[];
13
+ /**
14
+ * Adapt the raw LangGraph `["messages" | "updates", ...]` stream into a typed
15
+ * `AgentStreamChunk` stream for the application layer.
16
+ */
17
+ export declare function adaptRawStream(raw: AsyncIterable<RawStreamEntry>): AsyncGenerator<AgentStreamChunk>;
18
+ export {};
@@ -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,7 +1,7 @@
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
6
  export declare class AgentSessionStore {
7
7
  private getAdminforth;
@@ -17,4 +17,14 @@ export declare class AgentSessionStore {
17
17
  getLatestTurn(sessionId: string): Promise<any>;
18
18
  getChatSurfaceSessionId(incoming: ChatSurfaceIncomingMessage): string;
19
19
  getOrCreateChatSurfaceSession(incoming: ChatSurfaceIncomingMessage, adminUser: AdminUser): Promise<string>;
20
+ touchSession(sessionId: string): Promise<void>;
21
+ saveTurnResponse(input: {
22
+ turnId: string;
23
+ responseText: string;
24
+ debugHistory?: unknown;
25
+ }): Promise<void>;
26
+ getResumeState(sessionId: string): Promise<{
27
+ turnId: string;
28
+ initialResponse: string;
29
+ }>;
20
30
  }
@@ -86,4 +86,37 @@ export class AgentSessionStore {
86
86
  return sessionId;
87
87
  });
88
88
  }
89
+ touchSession(sessionId) {
90
+ return __awaiter(this, void 0, void 0, function* () {
91
+ yield this.getAdminforth().resource(this.options.sessionResource.resourceId).update(sessionId, {
92
+ [this.options.sessionResource.createdAtField]: new Date().toISOString(),
93
+ });
94
+ });
95
+ }
96
+ saveTurnResponse(input) {
97
+ return __awaiter(this, void 0, void 0, function* () {
98
+ const turnUpdates = {
99
+ [this.options.turnResource.responseField]: input.responseText,
100
+ };
101
+ if (this.options.turnResource.debugField) {
102
+ turnUpdates[this.options.turnResource.debugField] = input.debugHistory;
103
+ }
104
+ yield this.getAdminforth()
105
+ .resource(this.options.turnResource.resourceId)
106
+ .update(input.turnId, turnUpdates);
107
+ });
108
+ }
109
+ getResumeState(sessionId) {
110
+ return __awaiter(this, void 0, void 0, function* () {
111
+ const latestTurn = yield this.getLatestTurn(sessionId);
112
+ if (!latestTurn) {
113
+ throw new Error(`No agent turn found for session "${sessionId}".`);
114
+ }
115
+ const response = latestTurn[this.options.turnResource.responseField];
116
+ return {
117
+ turnId: latestTurn[this.options.turnResource.idField],
118
+ initialResponse: response === "not_finished" ? "" : String(response),
119
+ };
120
+ });
121
+ }
89
122
  }
@@ -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) {