@adminforth/agent 2.0.10 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/README.md +333 -10
  2. package/dist/application/ports.d.ts +66 -0
  3. package/dist/application/runTurnUseCase.d.ts +71 -0
  4. package/dist/application/runTurnUseCase.js +364 -0
  5. package/dist/custom/ChatFooter.vue +58 -30
  6. package/dist/custom/SteerDebugPanel.vue +45 -0
  7. package/dist/custom/SteerQueue.vue +54 -0
  8. package/dist/custom/composables/agentStore/constants.ts +1 -0
  9. package/dist/custom/composables/agentStore/useAgentSessions.ts +35 -16
  10. package/dist/custom/composables/agentStore/useAgentSteerQueue.ts +114 -0
  11. package/dist/custom/composables/useAgentStore.ts +46 -1
  12. package/dist/custom/conversation_area/MessageRenderer.vue +7 -1
  13. package/dist/custom/speech_recognition_frontend/AudioLines.vue +1 -1
  14. package/dist/custom/speech_recognition_frontend/MicrophoneButon.vue +3 -3
  15. package/dist/{agentEvents.d.ts → domain/agentEvents.d.ts} +5 -1
  16. package/dist/domain/steerBuffer.d.ts +33 -0
  17. package/dist/domain/steerBuffer.js +51 -0
  18. package/dist/{agent → domain}/systemPrompt.js +1 -1
  19. package/dist/{agent/turn → domain}/turnTypes.d.ts +41 -37
  20. package/dist/{agent/turn/VegaLiteStreamBuffer.d.ts → domain/vegaLiteStreamBuffer.d.ts} +1 -1
  21. package/dist/index.d.ts +4 -2
  22. package/dist/index.js +49 -35
  23. package/dist/{agent/runtime/AgentContext.d.ts → llm/agentContext.d.ts} +3 -3
  24. package/dist/{agent/simpleAgent.d.ts → llm/agentModels.d.ts} +18 -16
  25. package/dist/llm/agentModels.js +65 -0
  26. package/dist/{agent/runtime/AgentRuntime.d.ts → llm/agentRuntime.d.ts} +14 -2
  27. package/dist/{agent/runtime/AgentRuntime.js → llm/agentRuntime.js} +41 -6
  28. package/dist/llm/langGraphLlm.d.ts +25 -0
  29. package/dist/llm/langGraphLlm.js +54 -0
  30. package/dist/{agent/middleware/apiBasedTools.d.ts → llm/middleware/apiToolsMiddleware.d.ts} +1 -1
  31. package/dist/{agent/middleware/apiBasedTools.js → llm/middleware/apiToolsMiddleware.js} +8 -14
  32. package/dist/{agent → llm}/middleware/sequenceDebug.d.ts +1 -1
  33. package/dist/llm/middleware/steerMiddleware.d.ts +21 -0
  34. package/dist/llm/middleware/steerMiddleware.js +50 -0
  35. package/dist/{agent/models/AgentModelFactory.d.ts → llm/modelFactory.d.ts} +1 -1
  36. package/dist/{agent/models/AgentModelFactory.js → llm/modelFactory.js} +1 -1
  37. package/dist/llm/streamAdapter.d.ts +18 -0
  38. package/dist/llm/streamAdapter.js +117 -0
  39. package/dist/{sessionStore.d.ts → persistence/sessionStore.d.ts} +19 -2
  40. package/dist/{sessionStore.js → persistence/sessionStore.js} +53 -0
  41. package/dist/{agent/tools/AgentToolProvider.d.ts → tools/agentToolProvider.d.ts} +1 -1
  42. package/dist/{agent/tools/AgentToolProvider.js → tools/agentToolProvider.js} +1 -1
  43. package/dist/{apiBasedTools.js → tools/apiBasedTools.js} +0 -3
  44. package/dist/{agent/tools → tools}/apiTool.d.ts +1 -1
  45. package/dist/{agent/tools → tools}/fetchSkill.js +1 -1
  46. package/dist/{agent/tools → tools}/fetchToolSchema.d.ts +1 -1
  47. package/dist/{agent/tools → tools}/index.d.ts +1 -1
  48. package/dist/{agent/tools → tools}/navigateUser.d.ts +3 -3
  49. package/dist/{endpoints → transport/http}/context.d.ts +12 -4
  50. package/dist/transport/http/context.js +1 -0
  51. package/dist/{endpoints/core.js → transport/http/coreEndpoints.js} +23 -3
  52. package/dist/{endpoints/sessions.js → transport/http/sessionEndpoints.js} +36 -1
  53. package/dist/transport/sse/sseWriter.d.ts +29 -0
  54. package/dist/{surfaces/web-sse/createSseEventEmitter.js → transport/sse/sseWriter.js} +27 -0
  55. package/dist/{chatSurfaceService.d.ts → transport/surfaces/chatSurfaceService.d.ts} +3 -3
  56. package/dist/{chatSurfaceService.js → transport/surfaces/chatSurfaceService.js} +7 -5
  57. package/dist/{agent/speech/SpeechTurnService.d.ts → transport/surfaces/speechTurnService.d.ts} +1 -1
  58. package/dist/{agent/speech/SpeechTurnService.js → transport/surfaces/speechTurnService.js} +2 -2
  59. package/dist/types.d.ts +10 -4
  60. package/package.json +11 -2
  61. package/.woodpecker/buildRelease.sh +0 -13
  62. package/.woodpecker/buildSlackNotify.sh +0 -46
  63. package/.woodpecker/release.yml +0 -57
  64. package/agent/checkpointer.ts +0 -329
  65. package/agent/languageDetect.ts +0 -92
  66. package/agent/middleware/apiBasedTools.ts +0 -174
  67. package/agent/middleware/openAiResponsesContinuation.ts +0 -92
  68. package/agent/middleware/sequenceDebug.ts +0 -429
  69. package/agent/models/AgentModeResolver.ts +0 -9
  70. package/agent/models/AgentModelFactory.ts +0 -28
  71. package/agent/runtime/AgentContext.ts +0 -30
  72. package/agent/runtime/AgentRuntime.ts +0 -89
  73. package/agent/simpleAgent.ts +0 -199
  74. package/agent/skills/registry.ts +0 -162
  75. package/agent/speech/SpeechTurnService.ts +0 -179
  76. package/agent/systemPrompt.ts +0 -133
  77. package/agent/toolCallEvents.ts +0 -135
  78. package/agent/tools/AgentToolProvider.ts +0 -28
  79. package/agent/tools/apiTool.ts +0 -66
  80. package/agent/tools/fetchSkill.ts +0 -68
  81. package/agent/tools/fetchToolSchema.ts +0 -47
  82. package/agent/tools/getUserLocation.ts +0 -45
  83. package/agent/tools/index.ts +0 -31
  84. package/agent/tools/navigateUser.ts +0 -210
  85. package/agent/turn/TurnContextBuilder.ts +0 -36
  86. package/agent/turn/TurnLifecycleService.ts +0 -47
  87. package/agent/turn/TurnPersistenceService.ts +0 -33
  88. package/agent/turn/TurnPromptBuilder.ts +0 -51
  89. package/agent/turn/TurnStreamConsumer.ts +0 -69
  90. package/agent/turn/VegaLiteStreamBuffer.ts +0 -90
  91. package/agent/turn/turnTypes.ts +0 -100
  92. package/agentEvents.ts +0 -75
  93. package/agentTurnService.ts +0 -314
  94. package/apiBasedTools.ts +0 -712
  95. package/build.log +0 -67
  96. package/chatSurfaceService.ts +0 -319
  97. package/custom/ChatFooter.vue +0 -173
  98. package/custom/ChatHeader.vue +0 -78
  99. package/custom/ChatSurface.vue +0 -160
  100. package/custom/CustomAutoScrollContainer.vue +0 -164
  101. package/custom/SessionsHistory.vue +0 -88
  102. package/custom/chat.ts +0 -82
  103. package/custom/composables/agentAudio/utils.ts +0 -220
  104. package/custom/composables/agentStore/constants.ts +0 -19
  105. package/custom/composables/agentStore/pageContext.ts +0 -8
  106. package/custom/composables/agentStore/useAgentChat.ts +0 -241
  107. package/custom/composables/agentStore/useAgentPlaceholder.ts +0 -142
  108. package/custom/composables/agentStore/useAgentSessions.ts +0 -350
  109. package/custom/composables/useAgentAudio.ts +0 -272
  110. package/custom/composables/useAgentStore.ts +0 -510
  111. package/custom/composables/useAgentTransitions.ts +0 -58
  112. package/custom/conversation_area/ConversationArea.vue +0 -301
  113. package/custom/conversation_area/MessageRenderer.vue +0 -49
  114. package/custom/conversation_area/ProcessingTimeline.vue +0 -286
  115. package/custom/conversation_area/ReasoningRenderer.vue +0 -79
  116. package/custom/conversation_area/SystemMessageRenderer.vue +0 -28
  117. package/custom/conversation_area/TextRenderer.vue +0 -182
  118. package/custom/conversation_area/ThreeDotsAnimation.vue +0 -35
  119. package/custom/conversation_area/ToolApprovalRenderer.vue +0 -98
  120. package/custom/conversation_area/ToolRenderer.vue +0 -178
  121. package/custom/conversation_area/ToolsGroup.vue +0 -59
  122. package/custom/env.d.ts +0 -7
  123. package/custom/incremark_code_renderers/IncremarkShikiCodeBlock.vue +0 -393
  124. package/custom/incremark_code_renderers/incremarkCodeHighlight.ts +0 -285
  125. package/custom/incremark_code_renderers/incremarkRenderer.ts +0 -653
  126. package/custom/incremark_code_renderers/renderIncremarkMarkdown.ts +0 -118
  127. package/custom/package.json +0 -30
  128. package/custom/pnpm-lock.yaml +0 -2394
  129. package/custom/public/agentAudio/agent-processing.mp3 +0 -0
  130. package/custom/skills/analyze_data/SKILL.md +0 -25
  131. package/custom/skills/charts/SKILL.md +0 -193
  132. package/custom/skills/fetch_data/SKILL.md +0 -31
  133. package/custom/skills/mutate_data/SKILL.md +0 -121
  134. package/custom/speech_recognition_frontend/AudioLines.vue +0 -43
  135. package/custom/speech_recognition_frontend/MicrophoneButon.vue +0 -185
  136. package/custom/speech_recognition_frontend/types/voice-activity-detection.d.ts +0 -22
  137. package/custom/speech_recognition_frontend/voiceActivityDetection.ts +0 -62
  138. package/custom/tsconfig.json +0 -15
  139. package/custom/types.ts +0 -108
  140. package/custom/utils.ts +0 -38
  141. package/dist/agent/middleware/openAiResponsesContinuation.d.ts +0 -1
  142. package/dist/agent/middleware/openAiResponsesContinuation.js +0 -66
  143. package/dist/agent/models/AgentModeResolver.d.ts +0 -9
  144. package/dist/agent/models/AgentModeResolver.js +0 -9
  145. package/dist/agent/simpleAgent.js +0 -118
  146. package/dist/agent/turn/TurnContextBuilder.d.ts +0 -14
  147. package/dist/agent/turn/TurnContextBuilder.js +0 -31
  148. package/dist/agent/turn/TurnLifecycleService.d.ts +0 -24
  149. package/dist/agent/turn/TurnLifecycleService.js +0 -47
  150. package/dist/agent/turn/TurnPersistenceService.d.ts +0 -13
  151. package/dist/agent/turn/TurnPersistenceService.js +0 -35
  152. package/dist/agent/turn/TurnPromptBuilder.d.ts +0 -19
  153. package/dist/agent/turn/TurnPromptBuilder.js +0 -43
  154. package/dist/agent/turn/TurnStreamConsumer.d.ts +0 -11
  155. package/dist/agent/turn/TurnStreamConsumer.js +0 -84
  156. package/dist/agentTurnService.d.ts +0 -24
  157. package/dist/agentTurnService.js +0 -269
  158. package/dist/surfaces/web-sse/createSseEventEmitter.d.ts +0 -14
  159. package/endpoints/chatSurfaces.ts +0 -66
  160. package/endpoints/context.ts +0 -52
  161. package/endpoints/core.ts +0 -181
  162. package/endpoints/sessions.ts +0 -183
  163. package/errors.ts +0 -10
  164. package/index.ts +0 -192
  165. package/pnpm-workspace.yaml +0 -4
  166. package/sanitizeSpeechText.ts +0 -32
  167. package/sessionStore.ts +0 -105
  168. package/surfaces/web-sse/createSseEventEmitter.ts +0 -311
  169. package/tsconfig.json +0 -14
  170. package/types.ts +0 -127
  171. /package/dist/{agent/turn/turnTypes.js → application/ports.js} +0 -0
  172. /package/dist/{agentEvents.js → domain/agentEvents.js} +0 -0
  173. /package/dist/{agent → domain}/languageDetect.d.ts +0 -0
  174. /package/dist/{agent → domain}/languageDetect.js +0 -0
  175. /package/dist/{agent → domain}/systemPrompt.d.ts +0 -0
  176. /package/dist/{agent → domain}/toolCallEvents.d.ts +0 -0
  177. /package/dist/{agent → domain}/toolCallEvents.js +0 -0
  178. /package/dist/{endpoints/context.js → domain/turnTypes.js} +0 -0
  179. /package/dist/{agent/turn/VegaLiteStreamBuffer.js → domain/vegaLiteStreamBuffer.js} +0 -0
  180. /package/dist/{agent/runtime/AgentContext.js → llm/agentContext.js} +0 -0
  181. /package/dist/{agent → llm}/middleware/sequenceDebug.js +0 -0
  182. /package/dist/{agent/checkpointer.d.ts → persistence/checkpointStore.d.ts} +0 -0
  183. /package/dist/{agent/checkpointer.js → persistence/checkpointStore.js} +0 -0
  184. /package/dist/{errors.d.ts → shared/errors.d.ts} +0 -0
  185. /package/dist/{errors.js → shared/errors.js} +0 -0
  186. /package/dist/{sanitizeSpeechText.d.ts → shared/sanitizeSpeechText.d.ts} +0 -0
  187. /package/dist/{sanitizeSpeechText.js → shared/sanitizeSpeechText.js} +0 -0
  188. /package/dist/{apiBasedTools.d.ts → tools/apiBasedTools.d.ts} +0 -0
  189. /package/dist/{agent/tools → tools}/apiTool.js +0 -0
  190. /package/dist/{agent/tools → tools}/fetchSkill.d.ts +0 -0
  191. /package/dist/{agent/tools → tools}/fetchToolSchema.js +0 -0
  192. /package/dist/{agent/tools → tools}/getUserLocation.d.ts +0 -0
  193. /package/dist/{agent/tools → tools}/getUserLocation.js +0 -0
  194. /package/dist/{agent/tools → tools}/index.js +0 -0
  195. /package/dist/{agent/tools → tools}/navigateUser.js +0 -0
  196. /package/dist/{agent → tools}/skills/registry.d.ts +0 -0
  197. /package/dist/{agent → tools}/skills/registry.js +0 -0
  198. /package/dist/{endpoints/chatSurfaces.d.ts → transport/http/chatSurfaceEndpoints.d.ts} +0 -0
  199. /package/dist/{endpoints/chatSurfaces.js → transport/http/chatSurfaceEndpoints.js} +0 -0
  200. /package/dist/{endpoints/core.d.ts → transport/http/coreEndpoints.d.ts} +0 -0
  201. /package/dist/{endpoints/sessions.d.ts → transport/http/sessionEndpoints.d.ts} +0 -0
@@ -1,174 +0,0 @@
1
- import { ToolMessage } from "@langchain/core/messages";
2
- import { isGraphInterrupt } from "@langchain/langgraph";
3
- import { createMiddleware } from "langchain";
4
- import { logger, type AdminUser, type IAdminForth } from "adminforth";
5
- import {
6
- formatApiBasedToolCall,
7
- type ApiBasedTool,
8
- } from "../../apiBasedTools.js";
9
- import {
10
- createToolCallTracker,
11
- type ToolCallEventSink,
12
- } from "../toolCallEvents.js";
13
- import { ALWAYS_AVAILABLE_API_TOOL_NAMES } from "../tools/index.js";
14
- import { createApiTool } from "../tools/apiTool.js";
15
- import type { AgentEventEmitter } from "../../agentEvents.js";
16
- import type { SequenceDebugCollector } from "./sequenceDebug.js";
17
- import { isAbortError } from "../../errors.js";
18
-
19
- function getEnabledApiToolNames(messages: unknown[]) {
20
- const enabledToolNames = new Set<string>();
21
-
22
- for (const message of messages) {
23
- if (!ToolMessage.isInstance(message) || message.name !== "fetch_tool_schema") {
24
- continue;
25
- }
26
-
27
- const content =
28
- typeof message.content === "string"
29
- ? message.content
30
- : Array.isArray(message.content)
31
- ? message.content
32
- .map((block) =>
33
- typeof block === "string"
34
- ? block
35
- : "text" in block
36
- ? block.text
37
- : "",
38
- )
39
- .join("")
40
- : "";
41
-
42
- try {
43
- const parsed = JSON.parse(content) as { status?: number; name?: string };
44
-
45
- if (parsed.status === 200 && parsed.name) {
46
- enabledToolNames.add(parsed.name);
47
- }
48
- } catch {}
49
- }
50
-
51
- return enabledToolNames;
52
- }
53
-
54
- export function createApiBasedToolsMiddleware(
55
- apiBasedTools: Record<string, ApiBasedTool>,
56
- adminforth: IAdminForth,
57
- ) {
58
- const alwaysAvailableApiToolNames = new Set<string>(ALWAYS_AVAILABLE_API_TOOL_NAMES);
59
- const dynamicTools = Object.fromEntries(
60
- Object.entries(apiBasedTools).map(([toolName, apiBasedTool]) => [
61
- toolName,
62
- createApiTool(toolName, apiBasedTool),
63
- ]),
64
- );
65
-
66
- return createMiddleware({
67
- name: "ApiBasedToolsMiddleware",
68
- async wrapModelCall(request, handler) {
69
- const enabledApiToolNames = getEnabledApiToolNames(request.state.messages);
70
- const tools = [...enabledApiToolNames]
71
- .filter((toolName) => !alwaysAvailableApiToolNames.has(toolName))
72
- .map((toolName) => dynamicTools[toolName]);
73
- const availableTools = [...request.tools, ...tools];
74
-
75
- logger.info(
76
- `AdminForth Agent callable tools: ${availableTools.map((tool) => tool.name).join(", ")}`,
77
- );
78
-
79
- return handler({
80
- ...request,
81
- tools: availableTools,
82
- });
83
- },
84
- async wrapToolCall(request, handler) {
85
- const startedAt = Date.now();
86
- const toolInput = JSON.stringify(request.toolCall.args ?? {});
87
- if (!request.toolCall.id) {
88
- throw new Error(`Tool call "${request.toolCall.name}" has no id.`);
89
- }
90
-
91
- const toolCallId = request.toolCall.id;
92
- const { adminUser, abortSignal, emit, sequenceDebugSink, userTimeZone } = request.runtime.context as {
93
- adminUser: AdminUser;
94
- abortSignal?: AbortSignal;
95
- emit?: AgentEventEmitter;
96
- sequenceDebugSink: SequenceDebugCollector;
97
- userTimeZone: string;
98
- };
99
- const emitToolCall: ToolCallEventSink = (event) => {
100
- sequenceDebugSink.handleToolCallEvent(event);
101
- void emit?.({
102
- type: "tool-call",
103
- data: event,
104
- });
105
- };
106
- const toolArgs = (request.toolCall.args ?? {}) as Record<string, unknown>;
107
- let toolInfo: string | undefined;
108
-
109
- if (request.toolCall.name === "fetch_skill") {
110
- toolInfo = `Load ${(toolArgs.skillName as string).split("_").join(" ")} skill`;
111
- } else if (request.toolCall.name === "fetch_tool_schema") {
112
- toolInfo = `Load ${(toolArgs.toolName as string).split("_").join(" ")} tool `;
113
- } else {
114
- toolInfo = await formatApiBasedToolCall({
115
- adminforth,
116
- adminUser,
117
- inputs: toolArgs,
118
- toolName: request.toolCall.name,
119
- userTimeZone,
120
- });
121
- }
122
- const toolCallTracker = createToolCallTracker({
123
- emit: emitToolCall,
124
- toolCallId,
125
- toolName: request.toolCall.name,
126
- toolInfo,
127
- input: toolArgs,
128
- startedAt,
129
- });
130
- toolCallTracker.start();
131
- logger.info(
132
- `Invoking tool "${request.toolCall.name}" with input: ${toolInput}`,
133
- );
134
-
135
- try {
136
-
137
- const result = getEnabledApiToolNames(request.state.messages).has(request.toolCall.name)
138
- ? await handler({
139
- ...request,
140
- tool: dynamicTools[request.toolCall.name],
141
- })
142
- : await handler(request);
143
-
144
- toolCallTracker.finishSuccess(result);
145
- return result;
146
- } catch (error) {
147
- if (
148
- isGraphInterrupt(error)
149
- || abortSignal?.aborted
150
- || isAbortError(error)
151
- ) {
152
- throw error;
153
- }
154
-
155
- const message = error instanceof Error ? error.message : String(error);
156
-
157
- logger.error(
158
- `Error calling tool "${request.toolCall.name}": ${error instanceof Error ? error.stack ?? error.message : String(error)}`,
159
- );
160
- toolCallTracker.finishError(`Error: ${message}`);
161
- return new ToolMessage({
162
- name: request.toolCall.name,
163
- tool_call_id: toolCallId,
164
- status: "error",
165
- content: `Error: ${message}`,
166
- })
167
- } finally {
168
- logger.info(
169
- `Tool "${request.toolCall.name}" finished in ${Date.now() - startedAt}ms`,
170
- );
171
- }
172
- },
173
- });
174
- }
@@ -1,92 +0,0 @@
1
- import { AIMessage } from "@langchain/core/messages";
2
- import { createMiddleware } from "langchain";
3
-
4
- type OpenAiResponsesMetadata = {
5
- id?: string;
6
- };
7
-
8
- type OpenAiResponsesContext = {
9
- sessionId: string;
10
- turnId: string;
11
- };
12
-
13
- function getTurnKey(context: OpenAiResponsesContext) {
14
- return `${context.sessionId}:${context.turnId}`;
15
- }
16
-
17
- function getResponseId(message: AIMessage) {
18
- const metadata = message.response_metadata as OpenAiResponsesMetadata | undefined;
19
- return metadata?.id ?? null;
20
- }
21
-
22
- function getPreviousResponseId(modelSettings?: Record<string, unknown>) {
23
- return (modelSettings as { previous_response_id?: string } | undefined)
24
- ?.previous_response_id;
25
- }
26
-
27
- function getContinuationMessages<T extends { response_metadata?: unknown }>(
28
- messages: T[],
29
- previousResponseId: string,
30
- ) {
31
- let continuationStartIndex: number | null = null;
32
-
33
- for (let index = messages.length - 1; index >= 0; index -= 1) {
34
- const message = messages[index];
35
-
36
- if (
37
- AIMessage.isInstance(message) &&
38
- (message.response_metadata as OpenAiResponsesMetadata | undefined)?.id ===
39
- previousResponseId
40
- ) {
41
- continuationStartIndex = index + 1;
42
- break;
43
- }
44
- }
45
-
46
- if (continuationStartIndex === null) {
47
- return null;
48
- }
49
-
50
- return messages.slice(continuationStartIndex);
51
- }
52
-
53
- export function createOpenAiResponsesContinuationMiddleware() {
54
- const responseIdsByTurn = new Map<string, string>();
55
-
56
- return createMiddleware({
57
- name: "OpenAiResponsesContinuationMiddleware",
58
- async wrapModelCall(request, handler) {
59
- const context = request.runtime.context as OpenAiResponsesContext;
60
- const turnKey = getTurnKey(context);
61
- const previousResponseId =
62
- getPreviousResponseId(request.modelSettings) ??
63
- responseIdsByTurn.get(turnKey);
64
- const continuationMessages = previousResponseId
65
- ? getContinuationMessages(request.messages, previousResponseId)
66
- : null;
67
-
68
- const response = await handler(
69
- previousResponseId && continuationMessages
70
- ? {
71
- ...request,
72
- messages: continuationMessages,
73
- modelSettings: {
74
- ...request.modelSettings,
75
- previous_response_id: previousResponseId,
76
- },
77
- }
78
- : request,
79
- ) as AIMessage;
80
-
81
- const responseId = getResponseId(response);
82
-
83
- if (responseId) {
84
- responseIdsByTurn.set(turnKey, responseId);
85
- } else {
86
- responseIdsByTurn.delete(turnKey);
87
- }
88
-
89
- return response;
90
- },
91
- });
92
- }
@@ -1,429 +0,0 @@
1
- import { AIMessage } from "@langchain/core/messages";
2
- import { createMiddleware } from "langchain";
3
- import YAML from "yaml";
4
- import type { ToolCallEvent } from "../toolCallEvents.js";
5
-
6
- export type SequenceDebugResultType = "tool_calls" | "final_text";
7
-
8
- type SequenceDebugToolCall = {
9
- toolCallId: string;
10
- toolName: string;
11
- input: string;
12
- output: string | null;
13
- error: string | null;
14
- };
15
-
16
- type PendingSequenceDebugToolCall = SequenceDebugToolCall & {
17
- completed: boolean;
18
- };
19
-
20
- export type SequenceDebug = {
21
- sequenceId: number;
22
- startedAt: string;
23
- prompt: string;
24
- promptTokens: number;
25
- reasoning: string;
26
- reasoningTokens: number;
27
- text: string;
28
- textTokens: number;
29
- uncachedInputTokens: number;
30
- cachedInputTokens: number;
31
- outputTokens: number;
32
- cachedTokens: number;
33
- responseId: string | null;
34
- toolCalls: SequenceDebugToolCall[];
35
- endedAt: string;
36
- resultType: SequenceDebugResultType;
37
- };
38
-
39
- type PendingSequenceDebug = Omit<SequenceDebug, "toolCalls" | "endedAt" | "resultType"> & {
40
- toolCalls: PendingSequenceDebugToolCall[];
41
- pendingToolCalls: number;
42
- resultType: SequenceDebugResultType | null;
43
- };
44
-
45
- type SequenceDebugModelCall = {
46
- promptTokens: number;
47
- reasoning: string;
48
- reasoningTokens: number;
49
- text: string;
50
- textTokens: number;
51
- uncachedInputTokens: number;
52
- cachedInputTokens: number;
53
- outputTokens: number;
54
- cachedTokens: number;
55
- responseId: string | null;
56
- resultType: SequenceDebugResultType;
57
- };
58
-
59
- type OpenAiUsageMetadata = {
60
- input_tokens?: number;
61
- output_tokens?: number;
62
- input_token_details?: {
63
- cache_read?: number;
64
- };
65
- };
66
-
67
- type OpenAiResponseMetadata = {
68
- id?: string;
69
- };
70
-
71
- export type SequenceDebugModelCallSink = {
72
- handleModelCallStart: (prompt: string) => void;
73
- handleModelCallComplete: (params: SequenceDebugModelCall) => void;
74
- };
75
-
76
- export type SequenceDebugCollector = SequenceDebugModelCallSink & {
77
- handleToolCallEvent: (event: ToolCallEvent) => void;
78
- flush: () => void;
79
- getHistory: () => SequenceDebug[];
80
- };
81
-
82
- function createPendingSequenceDebug(sequenceId: number): PendingSequenceDebug {
83
- return {
84
- sequenceId,
85
- startedAt: new Date().toISOString(),
86
- prompt: "",
87
- promptTokens: 0,
88
- reasoning: "",
89
- reasoningTokens: 0,
90
- text: "",
91
- textTokens: 0,
92
- uncachedInputTokens: 0,
93
- cachedInputTokens: 0,
94
- outputTokens: 0,
95
- cachedTokens: 0,
96
- responseId: null,
97
- toolCalls: [],
98
- pendingToolCalls: 0,
99
- resultType: null,
100
- };
101
- }
102
-
103
- function hasSequenceDebugContent(sequence: PendingSequenceDebug | null): sequence is PendingSequenceDebug {
104
- return Boolean(
105
- sequence &&
106
- (
107
- sequence.prompt ||
108
- sequence.reasoning ||
109
- sequence.text ||
110
- sequence.toolCalls.length > 0
111
- ),
112
- );
113
- }
114
-
115
- function finalizeSequenceDebug(sequence: PendingSequenceDebug): SequenceDebug {
116
- return {
117
- sequenceId: sequence.sequenceId,
118
- startedAt: sequence.startedAt,
119
- prompt: sequence.prompt,
120
- promptTokens: sequence.promptTokens,
121
- reasoning: sequence.reasoning,
122
- reasoningTokens: sequence.reasoningTokens,
123
- text: sequence.text,
124
- textTokens: sequence.textTokens,
125
- uncachedInputTokens: sequence.uncachedInputTokens,
126
- cachedInputTokens: sequence.cachedInputTokens,
127
- outputTokens: sequence.outputTokens,
128
- cachedTokens: sequence.cachedTokens,
129
- responseId: sequence.responseId,
130
- toolCalls: sequence.toolCalls.map(({ completed: _completed, ...toolCall }) => toolCall),
131
- endedAt: new Date().toISOString(),
132
- resultType: sequence.resultType ?? "final_text",
133
- };
134
- }
135
-
136
- type SequenceDebugPromptModel = {
137
- getName?: () => string;
138
- model?: string;
139
- _defaultConfig?: {
140
- modelProvider?: string;
141
- };
142
- invocationParams?: (options?: Record<string, unknown>) => Record<string, unknown>;
143
- };
144
-
145
- function getDebugModelName(model: SequenceDebugPromptModel) {
146
- return typeof model.getName === "function" ? model.getName() : undefined;
147
- }
148
-
149
- function getDebugToolName(tool: unknown) {
150
- if (!tool || typeof tool !== "object") {
151
- return null;
152
- }
153
-
154
- const name = (tool as { name?: unknown }).name;
155
- return typeof name === "string" ? name : null;
156
- }
157
-
158
- function formatToolsForDebug(tools: unknown[]) {
159
- return tools.map((tool) => ({
160
- name: getDebugToolName(tool),
161
- }));
162
- }
163
-
164
- function stringifyPromptForDebug(params: {
165
- model: SequenceDebugPromptModel;
166
- systemMessage: { text: string };
167
- messages: unknown[];
168
- tools: unknown[];
169
- toolChoice?: unknown;
170
- modelSettings?: Record<string, unknown>;
171
- }) {
172
- const { model, systemMessage, messages, tools, toolChoice, modelSettings } = params;
173
- const invocationParams =
174
- typeof model.invocationParams === "function"
175
- ? model.invocationParams({
176
- ...(modelSettings ?? {}),
177
- ...(tools.length > 0 ? { tools } : {}),
178
- ...(toolChoice !== undefined ? { tool_choice: toolChoice } : {}),
179
- })
180
- : null;
181
-
182
- return YAML.stringify({
183
- model: {
184
- name: getDebugModelName(model) ?? null,
185
- provider: model._defaultConfig?.modelProvider ?? null,
186
- configuredModel:
187
- typeof model.model === "string" ? model.model : null,
188
- },
189
- systemMessage,
190
- messages,
191
- ...(tools.length > 0 ? { tools: formatToolsForDebug(tools) } : {}),
192
- ...(toolChoice !== undefined ? { toolChoice } : {}),
193
- ...(modelSettings ? { modelSettings } : {}),
194
- ...(invocationParams ? { invocationParams } : {}),
195
- });
196
- }
197
-
198
- function getMessageBlocks(message: {
199
- contentBlocks?: unknown;
200
- content?: unknown;
201
- }) {
202
- if (Array.isArray(message.contentBlocks)) {
203
- return message.contentBlocks;
204
- }
205
-
206
- if (Array.isArray(message.content)) {
207
- return message.content;
208
- }
209
-
210
- return [];
211
- }
212
-
213
- function hasToolCallSignal(message: {
214
- tool_calls?: unknown;
215
- tool_call_chunks?: unknown;
216
- additional_kwargs?: { tool_calls?: unknown };
217
- }) {
218
- return Boolean(
219
- (Array.isArray(message.tool_calls) && message.tool_calls.length > 0) ||
220
- (Array.isArray(message.tool_call_chunks) && message.tool_call_chunks.length > 0) ||
221
- (Array.isArray(message.additional_kwargs?.tool_calls) &&
222
- message.additional_kwargs.tool_calls.length > 0),
223
- );
224
- }
225
-
226
- function hasTokenCounter(model: unknown): model is {
227
- getNumTokens: (content: string) => Promise<number>;
228
- } {
229
- return (
230
- typeof model === "object" &&
231
- model !== null &&
232
- "getNumTokens" in model &&
233
- typeof model.getNumTokens === "function"
234
- );
235
- }
236
-
237
- async function countTokens(model: unknown, content: string) {
238
- if (!content) {
239
- return 0;
240
- }
241
-
242
- if (!hasTokenCounter(model)) {
243
- return 0;
244
- }
245
-
246
- return await model.getNumTokens(content);
247
- }
248
-
249
- function extractSequenceResponseDebug(message: AIMessage): SequenceDebugModelCall {
250
- const usageMetadata = message.usage_metadata as OpenAiUsageMetadata | undefined;
251
- const promptTokens = usageMetadata?.input_tokens ?? 0;
252
- const cachedInputTokens = usageMetadata?.input_token_details?.cache_read ?? 0;
253
- const blocks = getMessageBlocks(message);
254
- const reasoning = blocks
255
- .filter((block: any) => block?.type === "reasoning")
256
- .map((block: any) => String(block.reasoning ?? ""))
257
- .join("");
258
- const textFromBlocks = blocks
259
- .filter((block: any) => block?.type === "text")
260
- .map((block: any) => String(block.text ?? ""))
261
- .join("");
262
-
263
- return {
264
- promptTokens,
265
- reasoning,
266
- reasoningTokens: 0,
267
- text: textFromBlocks || (typeof message.content === "string" ? message.content : ""),
268
- textTokens: 0,
269
- uncachedInputTokens: Math.max(promptTokens - cachedInputTokens, 0),
270
- cachedInputTokens,
271
- outputTokens: usageMetadata?.output_tokens ?? 0,
272
- cachedTokens: cachedInputTokens,
273
- responseId:
274
- (message.response_metadata as OpenAiResponseMetadata | undefined)?.id ??
275
- null,
276
- resultType: hasToolCallSignal(message) ? "tool_calls" : "final_text",
277
- };
278
- }
279
-
280
- export function createSequenceDebugCollector(): SequenceDebugCollector {
281
- let nextSequenceId = 1;
282
- let currentSequenceDebug: PendingSequenceDebug | null = null;
283
- const history: SequenceDebug[] = [];
284
-
285
- const ensureSequenceDebug = () => {
286
- if (!currentSequenceDebug) {
287
- currentSequenceDebug = createPendingSequenceDebug(nextSequenceId++);
288
- }
289
-
290
- return currentSequenceDebug;
291
- };
292
-
293
- const flush = () => {
294
- if (!hasSequenceDebugContent(currentSequenceDebug)) {
295
- currentSequenceDebug = null;
296
- return;
297
- }
298
-
299
- const finalizedSequenceDebug = finalizeSequenceDebug(currentSequenceDebug);
300
- history.push(finalizedSequenceDebug);
301
- currentSequenceDebug = null;
302
- };
303
-
304
- return {
305
- handleModelCallStart(prompt) {
306
- if (
307
- currentSequenceDebug?.resultType &&
308
- currentSequenceDebug.pendingToolCalls === 0
309
- ) {
310
- flush();
311
- }
312
-
313
- const sequenceDebug = ensureSequenceDebug();
314
- sequenceDebug.prompt = prompt;
315
- },
316
- handleModelCallComplete(params) {
317
- const sequenceDebug = ensureSequenceDebug();
318
- sequenceDebug.promptTokens = params.promptTokens;
319
- sequenceDebug.reasoning = params.reasoning;
320
- sequenceDebug.reasoningTokens = params.reasoningTokens;
321
- sequenceDebug.text = params.text;
322
- sequenceDebug.textTokens = params.textTokens;
323
- sequenceDebug.uncachedInputTokens = params.uncachedInputTokens;
324
- sequenceDebug.cachedInputTokens = params.cachedInputTokens;
325
- sequenceDebug.outputTokens = params.outputTokens;
326
- sequenceDebug.cachedTokens = params.cachedTokens;
327
- sequenceDebug.responseId = params.responseId;
328
- sequenceDebug.resultType = params.resultType;
329
-
330
- if (
331
- sequenceDebug.resultType === "final_text" &&
332
- sequenceDebug.pendingToolCalls === 0
333
- ) {
334
- flush();
335
- }
336
- },
337
- handleToolCallEvent(event) {
338
- const sequenceDebug = ensureSequenceDebug();
339
-
340
- if (event.phase === "start") {
341
- sequenceDebug.toolCalls.push({
342
- toolCallId: event.toolCallId,
343
- toolName: event.toolName,
344
- input: event.input,
345
- output: null,
346
- error: null,
347
- completed: false,
348
- });
349
- sequenceDebug.pendingToolCalls += 1;
350
- return;
351
- }
352
-
353
- const pendingToolCall = sequenceDebug.toolCalls.find(
354
- (toolCall) => toolCall.toolCallId === event.toolCallId && !toolCall.completed,
355
- );
356
-
357
- if (pendingToolCall) {
358
- pendingToolCall.output = event.output;
359
- pendingToolCall.error = event.error;
360
- pendingToolCall.completed = true;
361
- } else {
362
- sequenceDebug.toolCalls.push({
363
- toolCallId: event.toolCallId,
364
- toolName: event.toolName,
365
- input: "",
366
- output: event.output,
367
- error: event.error,
368
- completed: true,
369
- });
370
- }
371
-
372
- sequenceDebug.pendingToolCalls = Math.max(
373
- 0,
374
- sequenceDebug.pendingToolCalls - 1,
375
- );
376
-
377
- if (
378
- sequenceDebug.resultType === "tool_calls" &&
379
- sequenceDebug.pendingToolCalls === 0
380
- ) {
381
- flush();
382
- }
383
- },
384
- flush,
385
- getHistory() {
386
- return history;
387
- },
388
- };
389
- }
390
-
391
- export function createSequenceDebugMiddleware(
392
- sink: SequenceDebugModelCallSink,
393
- ) {
394
- return createMiddleware({
395
- name: "SequenceDebugMiddleware",
396
- async wrapModelCall(request, handler) {
397
- const prompt = stringifyPromptForDebug({
398
- model: request.model as unknown as SequenceDebugPromptModel,
399
- systemMessage: request.systemMessage,
400
- messages: request.messages,
401
- tools: request.tools,
402
- toolChoice: request.toolChoice,
403
- modelSettings: request.modelSettings,
404
- });
405
-
406
- sink.handleModelCallStart(
407
- prompt,
408
- );
409
-
410
- const response = await handler(request) as AIMessage;
411
- const debug = extractSequenceResponseDebug(response);
412
- const [promptTokens, reasoningTokens, textTokens] = await Promise.all([
413
- debug.promptTokens || countTokens(request.model, prompt),
414
- countTokens(request.model, debug.reasoning),
415
- countTokens(request.model, debug.text),
416
- ]);
417
-
418
- sink.handleModelCallComplete({
419
- ...debug,
420
- promptTokens,
421
- reasoningTokens,
422
- textTokens,
423
- uncachedInputTokens: debug.promptTokens ? debug.uncachedInputTokens : promptTokens,
424
- outputTokens: debug.outputTokens || reasoningTokens + textTokens,
425
- });
426
- return response;
427
- },
428
- });
429
- }
@@ -1,9 +0,0 @@
1
- import type { PluginOptions } from "../../types.js";
2
-
3
- export class AgentModeResolver {
4
- constructor(private readonly options: PluginOptions) {}
5
-
6
- resolve(modeName?: string | null) {
7
- return this.options.modes.find((mode) => mode.name === modeName) ?? this.options.modes[0];
8
- }
9
- }