@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
@@ -1,329 +0,0 @@
1
- import type { RunnableConfig } from "@langchain/core/runnables";
2
- import {
3
- BaseCheckpointSaver,
4
- type Checkpoint,
5
- type CheckpointPendingWrite,
6
- type CheckpointMetadata,
7
- type CheckpointTuple,
8
- type PendingWrite,
9
- WRITES_IDX_MAP,
10
- } from "@langchain/langgraph-checkpoint";
11
- import type { PluginOptions } from "../types.js";
12
- import { Filters } from "adminforth";
13
-
14
- const ROOT_CHECKPOINT_NAMESPACE = "__root__";
15
- type CheckpointRow = Record<string, unknown>;
16
-
17
- export class AdminForthCheckpointSaver extends BaseCheckpointSaver {
18
- constructor(
19
- private readonly adminforth: any,
20
- private readonly pluginOptions: PluginOptions,
21
- ) {
22
- super();
23
- }
24
-
25
- private get resourceConfig() {
26
- const resource = this.pluginOptions.checkpointResource;
27
- if (!resource) {
28
- throw new Error("checkpointResource is not configured");
29
- }
30
- return resource;
31
- }
32
-
33
- private resource() {
34
- return this.adminforth.resource(this.resourceConfig.resourceId);
35
- }
36
-
37
- private serialize(value: unknown): string | null {
38
- if (value === undefined || value === null) return null;
39
- return JSON.stringify(value);
40
- }
41
-
42
- private deserialize<T>(value: unknown): T | null {
43
- if (value === undefined || value === null) return null;
44
- if (typeof value === "string") {
45
- return JSON.parse(value) as T;
46
- }
47
- return value as T;
48
- }
49
-
50
- private now(): string {
51
- return new Date().toISOString();
52
- }
53
-
54
- private encodeCheckpointNamespace(checkpointNs: string): string {
55
- return checkpointNs === "" ? ROOT_CHECKPOINT_NAMESPACE : checkpointNs;
56
- }
57
-
58
- private decodeCheckpointNamespace(checkpointNs: unknown): string {
59
- return checkpointNs === ROOT_CHECKPOINT_NAMESPACE ? "" : String(checkpointNs ?? "");
60
- }
61
-
62
- private getConfigValues(config: RunnableConfig) {
63
- const configurable = (config.configurable ?? {}) as Record<string, unknown>;
64
-
65
- return {
66
- threadId: String(configurable.thread_id ?? ""),
67
- checkpointNs: String(configurable.checkpoint_ns ?? ""),
68
- checkpointId: configurable.checkpoint_id
69
- ? String(configurable.checkpoint_id)
70
- : null,
71
- };
72
- }
73
-
74
- private buildConfig(threadId: string, checkpointNs: string, checkpointId: string): RunnableConfig {
75
- return {
76
- configurable: {
77
- thread_id: threadId,
78
- checkpoint_ns: checkpointNs,
79
- checkpoint_id: checkpointId,
80
- },
81
- };
82
- }
83
-
84
- private buildCheckpointRowId(threadId: string, checkpointNs: string, checkpointId: string) {
85
- return `cp:${threadId}:${checkpointNs}:${checkpointId}`;
86
- }
87
-
88
- private buildWritesRowId(
89
- threadId: string,
90
- checkpointNs: string,
91
- checkpointId: string,
92
- taskId: string,
93
- seq: number,
94
- ) {
95
- return `wr:${threadId}:${checkpointNs}:${checkpointId}:${taskId}:${seq}`;
96
- }
97
-
98
- private getWriteIndex(channel: string, index: number): number {
99
- return WRITES_IDX_MAP[channel] ?? index;
100
- }
101
-
102
- private isDuplicateCheckpointWriteError(error: unknown): boolean {
103
- return error instanceof Error && error.message.includes("UNIQUE constraint failed");
104
- }
105
-
106
- async put(
107
- config: RunnableConfig,
108
- checkpoint: Checkpoint,
109
- metadata: CheckpointMetadata,
110
- _newVersions: Record<string, unknown>,
111
- ): Promise<RunnableConfig> {
112
- const r = this.resourceConfig;
113
- const { threadId, checkpointNs } = this.getConfigValues(config);
114
- const checkpointId = String((checkpoint as any).id);
115
- const storedCheckpointNs = this.encodeCheckpointNamespace(checkpointNs);
116
-
117
- const parentCheckpointId = this.getConfigValues(config).checkpointId;
118
- const createdAt = this.now();
119
-
120
- await this.resource().create({
121
- [r.idField]: this.buildCheckpointRowId(threadId, storedCheckpointNs, checkpointId),
122
- [r.threadIdField]: threadId,
123
- [r.checkpointNamespaceField]: storedCheckpointNs,
124
- [r.checkpointIdField]: checkpointId,
125
- [r.parentCheckpointIdField]: parentCheckpointId,
126
- [r.rowKindField]: "checkpoint",
127
- [r.taskIdField]: null,
128
- [r.sequenceField]: 0,
129
- [r.createdAtField]: createdAt,
130
- [r.checkpointPayloadField]: this.serialize(checkpoint),
131
- [r.metadataPayloadField]: this.serialize(metadata),
132
- [r.writesPayloadField]: null,
133
- [r.schemaVersionField]: 1,
134
- });
135
-
136
- return this.buildConfig(threadId, checkpointNs, checkpointId);
137
- }
138
-
139
- async putWrites(
140
- config: RunnableConfig,
141
- writes: PendingWrite[],
142
- taskId: string,
143
- ): Promise<void> {
144
- const r = this.resourceConfig;
145
- const { threadId, checkpointNs, checkpointId } = this.getConfigValues(config);
146
- const storedCheckpointNs = this.encodeCheckpointNamespace(checkpointNs);
147
-
148
- if (!checkpointId) {
149
- throw new Error("putWrites requires checkpoint_id in config");
150
- }
151
-
152
- const createdAt = this.now();
153
-
154
- await Promise.all(
155
- writes.map(async ([channel, value], index) => {
156
- const writeIndex = this.getWriteIndex(channel, index);
157
-
158
- try {
159
- await this.resource().create({
160
- [r.idField]: this.buildWritesRowId(
161
- threadId,
162
- storedCheckpointNs,
163
- checkpointId,
164
- taskId,
165
- writeIndex,
166
- ),
167
- [r.threadIdField]: threadId,
168
- [r.checkpointNamespaceField]: storedCheckpointNs,
169
- [r.checkpointIdField]: checkpointId,
170
- [r.parentCheckpointIdField]: null,
171
- [r.rowKindField]: "writes",
172
- [r.taskIdField]: taskId,
173
- [r.sequenceField]: writeIndex,
174
- [r.createdAtField]: createdAt,
175
- [r.checkpointPayloadField]: null,
176
- [r.metadataPayloadField]: null,
177
- [r.writesPayloadField]: this.serialize([channel, value] satisfies PendingWrite),
178
- [r.schemaVersionField]: 1,
179
- });
180
- } catch (error) {
181
- if (!this.isDuplicateCheckpointWriteError(error)) {
182
- throw error;
183
- }
184
- }
185
- }),
186
- );
187
- }
188
-
189
- async getTuple(config: RunnableConfig): Promise<CheckpointTuple | undefined> {
190
- const r = this.resourceConfig;
191
- const { threadId, checkpointNs, checkpointId } = this.getConfigValues(config);
192
- const storedCheckpointNs = this.encodeCheckpointNamespace(checkpointNs);
193
-
194
- const checkpointRows = await this.resource().list(
195
- checkpointId
196
- ? Filters.AND(
197
- Filters.EQ(r.threadIdField, threadId),
198
- Filters.EQ(r.checkpointNamespaceField, storedCheckpointNs),
199
- Filters.EQ(r.checkpointIdField, checkpointId),
200
- Filters.EQ(r.rowKindField, "checkpoint"),
201
- )
202
- : Filters.AND(
203
- Filters.EQ(r.threadIdField, threadId),
204
- Filters.EQ(r.checkpointNamespaceField, storedCheckpointNs),
205
- Filters.EQ(r.rowKindField, "checkpoint"),
206
- ),
207
- 1,
208
- undefined,
209
- [{ field: r.checkpointIdField, direction: "desc" }],
210
- );
211
-
212
- const checkpointRow = checkpointRows[0];
213
- if (!checkpointRow) {
214
- return undefined;
215
- }
216
-
217
- const resolvedCheckpointId = String(checkpointRow[r.checkpointIdField]);
218
-
219
- const writesRows = await this.resource().list(
220
- Filters.AND(
221
- Filters.EQ(r.threadIdField, threadId),
222
- Filters.EQ(r.checkpointNamespaceField, storedCheckpointNs),
223
- Filters.EQ(r.checkpointIdField, resolvedCheckpointId),
224
- Filters.EQ(r.rowKindField, "writes"),
225
- ),
226
- undefined,
227
- undefined,
228
- [{ field: r.sequenceField, direction: "asc" }],
229
- );
230
-
231
- const pendingWrites: CheckpointPendingWrite[] = writesRows.flatMap((row: CheckpointRow) => {
232
- const taskId = String(row[r.taskIdField] ?? "");
233
- const write = this.deserialize<PendingWrite>(row[r.writesPayloadField]);
234
- if (!write) {
235
- return [];
236
- }
237
-
238
- const [channel, value] = write;
239
- return [[taskId, channel, value]];
240
- });
241
-
242
- const parentCheckpointId = checkpointRow[r.parentCheckpointIdField]
243
- ? String(checkpointRow[r.parentCheckpointIdField])
244
- : null;
245
-
246
- const tuple: CheckpointTuple = {
247
- config: this.buildConfig(threadId, checkpointNs, resolvedCheckpointId),
248
- checkpoint: this.deserialize<Checkpoint>(
249
- checkpointRow[r.checkpointPayloadField],
250
- ) as Checkpoint,
251
- metadata: (this.deserialize<CheckpointMetadata>(
252
- checkpointRow[r.metadataPayloadField],
253
- ) ?? {}) as CheckpointMetadata,
254
- parentConfig: parentCheckpointId
255
- ? this.buildConfig(threadId, checkpointNs, parentCheckpointId)
256
- : undefined,
257
- pendingWrites,
258
- };
259
-
260
- return tuple;
261
- }
262
-
263
- async *list(
264
- config: RunnableConfig,
265
- options?: {
266
- before?: RunnableConfig;
267
- limit?: number;
268
- },
269
- ): AsyncGenerator<CheckpointTuple> {
270
- const r = this.resourceConfig;
271
- const { threadId, checkpointNs } = this.getConfigValues(config);
272
- const storedCheckpointNs = this.encodeCheckpointNamespace(checkpointNs);
273
- const beforeCheckpointId = options?.before
274
- ? this.getConfigValues(options.before).checkpointId
275
- : null;
276
-
277
- const filters: Filters[] = [
278
- Filters.EQ(r.rowKindField, "checkpoint"),
279
- Filters.EQ(r.threadIdField, threadId),
280
- Filters.EQ(r.checkpointNamespaceField, storedCheckpointNs),
281
- ];
282
-
283
- if (beforeCheckpointId) {
284
- filters.push(Filters.LT(r.checkpointIdField, beforeCheckpointId));
285
- }
286
-
287
- const rows = await this.resource().list(
288
- Filters.AND(...filters),
289
- options?.limit,
290
- undefined,
291
- [{ field: r.checkpointIdField, direction: "desc" }],
292
- );
293
-
294
- for (const row of rows) {
295
- const tuple = await this.getTuple(
296
- this.buildConfig(
297
- String(row[r.threadIdField]),
298
- this.decodeCheckpointNamespace(row[r.checkpointNamespaceField]),
299
- String(row[r.checkpointIdField]),
300
- ),
301
- );
302
-
303
- if (tuple) {
304
- yield tuple;
305
- }
306
- }
307
- }
308
-
309
- async deleteThread(threadId: string, checkpointNs = ""): Promise<void> {
310
- const r = this.resourceConfig;
311
- const storedCheckpointNs = this.encodeCheckpointNamespace(checkpointNs);
312
-
313
- const rows = await this.resource().list(
314
- Filters.AND(
315
- Filters.EQ(r.threadIdField, threadId),
316
- Filters.EQ(r.checkpointNamespaceField, storedCheckpointNs),
317
- ),
318
- undefined,
319
- undefined,
320
- [{ field: r.createdAtField, direction: "desc" }],
321
- );
322
-
323
- for (const row of rows) {
324
- await this.adminforth
325
- .resource(this.pluginOptions.checkpointResource!.resourceId)
326
- .delete(row[r.idField]);
327
- }
328
- }
329
- }
@@ -1,92 +0,0 @@
1
- import { logger } from "adminforth";
2
- import type { PluginOptions } from "../types.js";
3
-
4
- export type DetectedLanguage = {
5
- language: string;
6
- code: string; // ISO 639-1
7
- ambiguous: boolean;
8
- };
9
-
10
- export type PreviousUserMessage = {
11
- text: string;
12
- };
13
-
14
- const USER_LANGUAGE_OUTPUT_SCHEMA = {
15
- name: "user_language",
16
- strict: true,
17
- schema: {
18
- type: "object",
19
- additionalProperties: false,
20
- properties: {
21
- language: {
22
- type: "string",
23
- description: "Full English language name, for example English, Ukrainian, French.",
24
- },
25
- code: {
26
- type: "string",
27
- description: "Uppercase ISO 639-1 two-letter language code, for example EN, UK, FR.",
28
- },
29
- ambiguous: {
30
- type: "boolean",
31
- description: "True if the user's language cannot be confidently detected from the message.",
32
- },
33
- },
34
- required: ["language", "code", "ambiguous"],
35
- },
36
- } as const;
37
-
38
- function parseUserLanguage(content: string | undefined): DetectedLanguage | null {
39
- if (!content) {
40
- return null;
41
- }
42
-
43
- try {
44
- const parsed = JSON.parse(content) as DetectedLanguage;
45
- return {
46
- language: parsed.language,
47
- code: parsed.code,
48
- ambiguous: parsed.ambiguous,
49
- };
50
- } catch (error) {
51
- logger.warn(`Failed to parse detected user language: ${error instanceof Error ? error.message : String(error)}`);
52
- return null;
53
- }
54
- }
55
-
56
- export async function detectUserLanguage(
57
- completionAdapter: PluginOptions["modes"][number]["completionAdapter"],
58
- prompt: string,
59
- previousUserMessages: PreviousUserMessage[] = [],
60
- ): Promise<DetectedLanguage | null> {
61
- const previousMessages = previousUserMessages.length
62
- ? [
63
- "",
64
- "Previous user messages:",
65
- ...previousUserMessages.map((message) => message.text),
66
- ]
67
- : [];
68
- const response = await completionAdapter.complete({
69
- content: [
70
- "Detect the language the assistant should use for the current user message.",
71
- "Use recent conversation context only to resolve short or ambiguous current messages.",
72
- "Return only the requested structured output.",
73
- "The language must be the full English language name.",
74
- "The code must be an uppercase ISO 639-1 two-letter code like UK, EN, FR.",
75
- "Set ambiguous to true if the response language cannot be confidently detected from the current message or context.",
76
- ...previousMessages,
77
- "",
78
- "Current user message:",
79
- prompt,
80
- ].join("\n"),
81
- maxTokens: 80,
82
- outputSchema: USER_LANGUAGE_OUTPUT_SCHEMA,
83
- reasoningEffort: "none",
84
- });
85
-
86
- if (response.error) {
87
- logger.warn(`Failed to detect user language: ${response.error}`);
88
- return null;
89
- }
90
-
91
- return parseUserLanguage(response.content);
92
- }
@@ -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
- }