@adminforth/agent 2.5.10 → 2.7.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.
- package/dist/application/ports.d.ts +1 -0
- package/dist/application/runTurnUseCase.d.ts +2 -0
- package/dist/application/runTurnUseCase.js +20 -17
- package/dist/custom/composables/agentStore/useAgentChat.ts +6 -0
- package/dist/custom/composables/useAgentStore.ts +2 -0
- package/dist/custom/conversation_area/ToolApprovalRenderer.vue +6 -0
- package/dist/domain/systemPrompt.d.ts +2 -3
- package/dist/domain/systemPrompt.js +3 -3
- package/dist/domain/turnTypes.d.ts +3 -5
- package/dist/llm/agentContext.d.ts +3 -0
- package/dist/llm/agentContext.js +1 -0
- package/dist/llm/agentModels.d.ts +1 -0
- package/dist/llm/agentRuntime.js +18 -1
- package/dist/llm/langGraphLlm.js +3 -4
- package/dist/llm/middleware/legacySystemMessages.d.ts +15 -0
- package/dist/llm/middleware/legacySystemMessages.js +45 -0
- package/dist/persistence/checkpointStore.d.ts +5 -0
- package/dist/persistence/checkpointStore.js +27 -17
- package/dist/transport/http/coreEndpoints.js +2 -0
- package/package.json +5 -5
|
@@ -60,6 +60,7 @@ export type RunTurnUseCaseDeps = {
|
|
|
60
60
|
export declare class RunTurnUseCase {
|
|
61
61
|
private readonly deps;
|
|
62
62
|
private readonly pendingInterrupts;
|
|
63
|
+
private readonly lastDetectedLanguage;
|
|
63
64
|
constructor(deps: RunTurnUseCaseDeps);
|
|
64
65
|
private resolveMode;
|
|
65
66
|
private buildContext;
|
|
@@ -78,6 +79,7 @@ export declare class RunTurnUseCase {
|
|
|
78
79
|
*/
|
|
79
80
|
private prepareEditTurn;
|
|
80
81
|
private prepareTurn;
|
|
82
|
+
private resolveUserLanguage;
|
|
81
83
|
private buildMessages;
|
|
82
84
|
private handleInterrupt;
|
|
83
85
|
private runAgentTurn;
|
|
@@ -17,7 +17,6 @@ var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
|
17
17
|
import { logger, Filters } from "adminforth";
|
|
18
18
|
import { randomUUID } from "crypto";
|
|
19
19
|
import { VegaLiteStreamBuffer } from "../domain/vegaLiteStreamBuffer.js";
|
|
20
|
-
import { buildAgentTurnSystemPrompt } from "../domain/systemPrompt.js";
|
|
21
20
|
import { getErrorMessage, isAbortError } from "../shared/errors.js";
|
|
22
21
|
function getApprovalDecision(input) {
|
|
23
22
|
return "approvalDecision" in input
|
|
@@ -77,6 +76,7 @@ export class RunTurnUseCase {
|
|
|
77
76
|
constructor(deps) {
|
|
78
77
|
this.deps = deps;
|
|
79
78
|
this.pendingInterrupts = new Map();
|
|
79
|
+
this.lastDetectedLanguage = new Map();
|
|
80
80
|
}
|
|
81
81
|
resolveMode(modeName) {
|
|
82
82
|
var _a;
|
|
@@ -175,6 +175,7 @@ export class RunTurnUseCase {
|
|
|
175
175
|
// Editing supersedes any in-flight turn state for this session.
|
|
176
176
|
this.deps.steerBuffer.clear(input.sessionId);
|
|
177
177
|
this.pendingInterrupts.delete(input.sessionId);
|
|
178
|
+
this.lastDetectedLanguage.delete(input.sessionId);
|
|
178
179
|
// Apply the edit + truncate (deletes later turns first, then rewrites the edited turn).
|
|
179
180
|
yield this.deps.sessions.editTurnAndTruncateAfter({
|
|
180
181
|
sessionId: input.sessionId,
|
|
@@ -239,9 +240,13 @@ export class RunTurnUseCase {
|
|
|
239
240
|
};
|
|
240
241
|
});
|
|
241
242
|
}
|
|
242
|
-
|
|
243
|
+
resolveUserLanguage(prepared) {
|
|
243
244
|
return __awaiter(this, void 0, void 0, function* () {
|
|
244
|
-
|
|
245
|
+
var _a;
|
|
246
|
+
if (prepared.resume) {
|
|
247
|
+
return (_a = this.lastDetectedLanguage.get(prepared.sessionId)) !== null && _a !== void 0 ? _a : null;
|
|
248
|
+
}
|
|
249
|
+
const detected = yield this.deps.llm
|
|
245
250
|
.detectLanguage({
|
|
246
251
|
completionAdapter: prepared.mode.completionAdapter,
|
|
247
252
|
prompt: prepared.prompt,
|
|
@@ -255,20 +260,13 @@ export class RunTurnUseCase {
|
|
|
255
260
|
logger.warn(`Failed to detect user language: ${getErrorMessage(error)}`);
|
|
256
261
|
return null;
|
|
257
262
|
});
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
agentSystemPrompt: yield this.deps.getAgentSystemPrompt(),
|
|
261
|
-
adminUser: prepared.context.adminUser,
|
|
262
|
-
usernameField: adminforth.config.auth.usernameField,
|
|
263
|
-
userLanguage,
|
|
264
|
-
chatSurface: prepared.context.chatSurface,
|
|
265
|
-
});
|
|
266
|
-
return [
|
|
267
|
-
{ role: "system", content: systemPrompt },
|
|
268
|
-
{ role: "user", content: prepared.prompt },
|
|
269
|
-
];
|
|
263
|
+
this.lastDetectedLanguage.set(prepared.sessionId, detected);
|
|
264
|
+
return detected;
|
|
270
265
|
});
|
|
271
266
|
}
|
|
267
|
+
buildMessages(prepared) {
|
|
268
|
+
return [{ role: "user", content: prepared.prompt }];
|
|
269
|
+
}
|
|
272
270
|
handleInterrupt(prepared, interrupt, descriptors) {
|
|
273
271
|
return __awaiter(this, void 0, void 0, function* () {
|
|
274
272
|
var _a, _b, _c;
|
|
@@ -290,6 +288,7 @@ export class RunTurnUseCase {
|
|
|
290
288
|
runAgentTurn(prepared) {
|
|
291
289
|
return __awaiter(this, void 0, void 0, function* () {
|
|
292
290
|
var _a, e_1, _b, _c;
|
|
291
|
+
const userLanguage = yield this.resolveUserLanguage(prepared);
|
|
293
292
|
const streamInput = prepared.resume
|
|
294
293
|
? {
|
|
295
294
|
resume: buildResumeValue({
|
|
@@ -298,11 +297,12 @@ export class RunTurnUseCase {
|
|
|
298
297
|
prompt: prepared.prompt,
|
|
299
298
|
}),
|
|
300
299
|
}
|
|
301
|
-
: { messages:
|
|
300
|
+
: { messages: this.buildMessages(prepared) };
|
|
302
301
|
const stream = yield this.deps.llm.streamTurn({
|
|
303
302
|
completionAdapter: prepared.mode.completionAdapter,
|
|
303
|
+
systemPrompt: yield this.deps.getAgentSystemPrompt(),
|
|
304
304
|
input: streamInput,
|
|
305
|
-
context: prepared.context,
|
|
305
|
+
context: Object.assign(Object.assign({}, prepared.context), { userLanguage }),
|
|
306
306
|
observability: prepared.observability,
|
|
307
307
|
branchFromCheckpointId: prepared.branchFromCheckpointId,
|
|
308
308
|
});
|
|
@@ -353,6 +353,9 @@ export class RunTurnUseCase {
|
|
|
353
353
|
// done and leftover (unconsumed) steers must not leak into the next turn.
|
|
354
354
|
if (!interrupted) {
|
|
355
355
|
this.deps.steerBuffer.clear(prepared.sessionId);
|
|
356
|
+
// The detected language is only needed to bridge an interrupt -> resume; once
|
|
357
|
+
// the turn is done the next one re-detects.
|
|
358
|
+
this.lastDetectedLanguage.delete(prepared.sessionId);
|
|
356
359
|
}
|
|
357
360
|
if (!this.deps.hasPersistentCheckpointer && !interrupted) {
|
|
358
361
|
this.pendingInterrupts.delete(prepared.sessionId);
|
|
@@ -134,6 +134,11 @@ export function createAgentChatManager({
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
function handleManualApprovalStreamPart(dataPart: any) {
|
|
137
|
+
if (dataPart?.type === 'error') {
|
|
138
|
+
const error = dataPart.errorText ?? dataPart.error;
|
|
139
|
+
throw new Error(typeof error === 'string' && error ? error : 'Agent approval failed');
|
|
140
|
+
}
|
|
141
|
+
|
|
137
142
|
if (dataPart?.type === 'text-delta' && typeof dataPart.delta === 'string') {
|
|
138
143
|
appendTextDelta(dataPart.delta);
|
|
139
144
|
return;
|
|
@@ -344,6 +349,7 @@ export function createAgentChatManager({
|
|
|
344
349
|
body: JSON.stringify({
|
|
345
350
|
sessionId,
|
|
346
351
|
decision,
|
|
352
|
+
mode: activeModeName.value,
|
|
347
353
|
}),
|
|
348
354
|
});
|
|
349
355
|
|
|
@@ -161,6 +161,7 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
161
161
|
|
|
162
162
|
if (approvalPart?.data) {
|
|
163
163
|
approvalPart.data.status = 'processing';
|
|
164
|
+
approvalPart.data.error = undefined;
|
|
164
165
|
}
|
|
165
166
|
|
|
166
167
|
try {
|
|
@@ -172,6 +173,7 @@ export const useAgentStore = defineStore('agent', () => {
|
|
|
172
173
|
} catch (error) {
|
|
173
174
|
if (approvalPart?.data) {
|
|
174
175
|
approvalPart.data.status = 'pending';
|
|
176
|
+
approvalPart.data.error = error instanceof Error ? error.message : String(error);
|
|
175
177
|
}
|
|
176
178
|
console.error('Error submitting tool approval', error);
|
|
177
179
|
}
|
|
@@ -70,6 +70,12 @@
|
|
|
70
70
|
{{ data.status === 'processing' ? $t('Processing') : data.status === 'approved' ? $t('Approved') : $t('Rejected') }}
|
|
71
71
|
</span>
|
|
72
72
|
</div>
|
|
73
|
+
<p
|
|
74
|
+
v-if="data.error"
|
|
75
|
+
class="mt-3 text-sm leading-5 text-red-600 dark:text-red-400"
|
|
76
|
+
>
|
|
77
|
+
{{ data.error }}
|
|
78
|
+
</p>
|
|
73
79
|
</div>
|
|
74
80
|
</div>
|
|
75
81
|
</div>
|
|
@@ -2,11 +2,10 @@ import type { AdminUser, IAdminForth } from "adminforth";
|
|
|
2
2
|
import type { DetectedLanguage } from "./languageDetect.js";
|
|
3
3
|
export declare const DEFAULT_AGENT_SYSTEM_PROMPT: string;
|
|
4
4
|
export declare function appendCustomSystemPrompt(systemPrompt: string, customSystemPrompt?: string): string;
|
|
5
|
-
export declare function
|
|
6
|
-
agentSystemPrompt: string;
|
|
5
|
+
export declare function buildDynamicSystemPrompt(input: {
|
|
7
6
|
adminUser: AdminUser;
|
|
8
7
|
usernameField: string;
|
|
9
|
-
userLanguage
|
|
8
|
+
userLanguage?: DetectedLanguage | null;
|
|
10
9
|
chatSurface?: string;
|
|
11
10
|
}): string;
|
|
12
11
|
export declare function buildAgentSystemPrompt(adminforth: IAdminForth, hiddenResourceIds?: Iterable<string>): Promise<string>;
|
|
@@ -51,14 +51,14 @@ function formatAdminUserPrompt(adminUser, usernameField) {
|
|
|
51
51
|
"Use this admin user email when the user asks to send information to themselves, the current admin, or the logged-in user.",
|
|
52
52
|
].join("\n");
|
|
53
53
|
}
|
|
54
|
-
export function
|
|
54
|
+
export function buildDynamicSystemPrompt(input) {
|
|
55
|
+
var _a;
|
|
55
56
|
return [
|
|
56
|
-
input.agentSystemPrompt,
|
|
57
57
|
formatAdminUserPrompt(input.adminUser, input.usernameField),
|
|
58
58
|
input.chatSurface
|
|
59
59
|
? `Current chat surface: ${input.chatSurface}. The user is not in the AdminForth web UI, so tools cannot move their browser. When navigate_user returns a link, send that link to the user.`
|
|
60
60
|
: "",
|
|
61
|
-
formatLanguagePrompt(input.userLanguage),
|
|
61
|
+
formatLanguagePrompt((_a = input.userLanguage) !== null && _a !== void 0 ? _a : null),
|
|
62
62
|
].filter(Boolean).join("\n\n");
|
|
63
63
|
}
|
|
64
64
|
function formatResources(resources) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AdminUser, AudioAdapter } from "adminforth";
|
|
2
|
+
import type { DetectedLanguage } from "./languageDetect.js";
|
|
2
3
|
import type { CurrentPageContext } from "../tools/getUserLocation.js";
|
|
3
4
|
import type { AgentEventEmitter } from "./agentEvents.js";
|
|
4
5
|
/**
|
|
@@ -53,6 +54,7 @@ export type AgentTurnContext = {
|
|
|
53
54
|
currentPage?: CurrentPageContext;
|
|
54
55
|
chatSurface?: string;
|
|
55
56
|
adminPublicOrigin?: string;
|
|
57
|
+
userLanguage?: DetectedLanguage | null;
|
|
56
58
|
};
|
|
57
59
|
export type AgentTurnObservability = {
|
|
58
60
|
emit?: AgentEventEmitter;
|
|
@@ -76,12 +78,8 @@ export type HandleSpeechTurnInput = SpeechAgentTurnInput;
|
|
|
76
78
|
export type HandleEditTurnInput = TextAgentTurnInput & {
|
|
77
79
|
turnId: string;
|
|
78
80
|
};
|
|
79
|
-
/**
|
|
80
|
-
* Provider-agnostic message passed from the application layer to the LLM port.
|
|
81
|
-
* The infrastructure adapter maps it onto concrete LangChain messages.
|
|
82
|
-
*/
|
|
83
81
|
export type AgentMessage = {
|
|
84
|
-
role: "
|
|
82
|
+
role: "user";
|
|
85
83
|
content: string;
|
|
86
84
|
};
|
|
87
85
|
/**
|
|
@@ -4,6 +4,7 @@ import type { AgentEventEmitter } from "../domain/agentEvents.js";
|
|
|
4
4
|
import type { SequenceDebugCollector } from "./middleware/sequenceDebug.js";
|
|
5
5
|
import type { CurrentPageContext } from "../tools/getUserLocation.js";
|
|
6
6
|
import type { AgentTurnContext } from "../domain/turnTypes.js";
|
|
7
|
+
import type { DetectedLanguage } from "../domain/languageDetect.js";
|
|
7
8
|
export declare const contextSchema: z.ZodObject<{
|
|
8
9
|
adminUser: z.ZodCustom<AdminUser, AdminUser>;
|
|
9
10
|
userTimeZone: z.ZodString;
|
|
@@ -14,9 +15,11 @@ export declare const contextSchema: z.ZodObject<{
|
|
|
14
15
|
chatSurface: z.ZodOptional<z.ZodString>;
|
|
15
16
|
adminBaseUrl: z.ZodOptional<z.ZodString>;
|
|
16
17
|
adminPublicOrigin: z.ZodOptional<z.ZodString>;
|
|
18
|
+
userLanguage: z.ZodOptional<z.ZodCustom<DetectedLanguage | null, DetectedLanguage | null>>;
|
|
17
19
|
emit: z.ZodOptional<z.ZodCustom<AgentEventEmitter, AgentEventEmitter>>;
|
|
18
20
|
sequenceDebugSink: z.ZodCustom<SequenceDebugCollector, SequenceDebugCollector>;
|
|
19
21
|
}, z.core.$strip>;
|
|
22
|
+
export type AgentContext = z.infer<typeof contextSchema>;
|
|
20
23
|
export declare function toLangchainAgentContext(context: AgentTurnContext & {
|
|
21
24
|
adminBaseUrl: string;
|
|
22
25
|
emit?: AgentEventEmitter;
|
package/dist/llm/agentContext.js
CHANGED
|
@@ -9,6 +9,7 @@ export const contextSchema = z.object({
|
|
|
9
9
|
chatSurface: z.string().optional(),
|
|
10
10
|
adminBaseUrl: z.string().optional(),
|
|
11
11
|
adminPublicOrigin: z.string().optional(),
|
|
12
|
+
userLanguage: z.custom().optional(),
|
|
12
13
|
emit: z.custom().optional(),
|
|
13
14
|
sequenceDebugSink: z.custom(),
|
|
14
15
|
});
|
package/dist/llm/agentRuntime.js
CHANGED
|
@@ -7,12 +7,14 @@ 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 { createAgent, summarizationMiddleware, humanInTheLoopMiddleware } from "langchain";
|
|
10
|
+
import { createAgent, summarizationMiddleware, humanInTheLoopMiddleware, dynamicSystemPromptMiddleware, } from "langchain";
|
|
11
11
|
import { createApiBasedToolsMiddleware } from "./middleware/apiToolsMiddleware.js";
|
|
12
12
|
import { createSequenceDebugMiddleware } from "./middleware/sequenceDebug.js";
|
|
13
13
|
import { createSteerMiddleware } from "./middleware/steerMiddleware.js";
|
|
14
14
|
import { createAgentLlmMetricsLogger } from "./agentModels.js";
|
|
15
15
|
import { contextSchema, toLangchainAgentContext } from "./agentContext.js";
|
|
16
|
+
import { createLegacySystemMessagesMiddleware } from "./middleware/legacySystemMessages.js";
|
|
17
|
+
import { buildDynamicSystemPrompt } from "../domain/systemPrompt.js";
|
|
16
18
|
function createHumanInTheLoopInterrupts(apiBasedTools) {
|
|
17
19
|
return Object.fromEntries(Object.entries(apiBasedTools)
|
|
18
20
|
.filter(([, apiBasedTool]) => { var _a; return ((_a = apiBasedTool.agent) === null || _a === void 0 ? void 0 : _a.isDangerous) === true; })
|
|
@@ -43,10 +45,20 @@ export class AgentRuntime {
|
|
|
43
45
|
descriptionPrefix: "Tool execution pending approval",
|
|
44
46
|
});
|
|
45
47
|
const steerMiddleware = createSteerMiddleware(this.options.steerBuffer);
|
|
48
|
+
const legacySystemMessagesMiddleware = createLegacySystemMessagesMiddleware();
|
|
49
|
+
const usernameField = adminforth.config.auth.usernameField;
|
|
50
|
+
const dynamicPromptMiddleware = dynamicSystemPromptMiddleware((_state, runtime) => buildDynamicSystemPrompt({
|
|
51
|
+
adminUser: runtime.context.adminUser,
|
|
52
|
+
usernameField,
|
|
53
|
+
userLanguage: runtime.context.userLanguage,
|
|
54
|
+
chatSurface: runtime.context.chatSurface,
|
|
55
|
+
}));
|
|
46
56
|
const middleware = [
|
|
47
57
|
steerMiddleware,
|
|
48
58
|
apiBasedToolsMiddleware,
|
|
49
59
|
hitlMiddleware,
|
|
60
|
+
legacySystemMessagesMiddleware,
|
|
61
|
+
dynamicPromptMiddleware,
|
|
50
62
|
...((_a = input.models.modelMiddleware) !== null && _a !== void 0 ? _a : []),
|
|
51
63
|
sequenceDebugMiddleware,
|
|
52
64
|
summarizationMiddleware({
|
|
@@ -58,6 +70,11 @@ export class AgentRuntime {
|
|
|
58
70
|
const agent = createAgent({
|
|
59
71
|
name: this.options.name,
|
|
60
72
|
model: input.models.model,
|
|
73
|
+
// Passed as a plain string on purpose: LangChain normalizes it to a single text
|
|
74
|
+
// block, and DynamicSystemPromptMiddleware appends the per-turn half as a second
|
|
75
|
+
// one. That block split is all the agent owes the provider — whether the boundary
|
|
76
|
+
// becomes a cache breakpoint is the adapter's call.
|
|
77
|
+
systemPrompt: input.systemPrompt,
|
|
61
78
|
checkpointer: this.options.getCheckpointer(),
|
|
62
79
|
tools,
|
|
63
80
|
contextSchema,
|
package/dist/llm/langGraphLlm.js
CHANGED
|
@@ -8,13 +8,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { Command } from "@langchain/langgraph";
|
|
11
|
-
import { HumanMessage
|
|
11
|
+
import { HumanMessage } from "langchain";
|
|
12
12
|
import { detectUserLanguage } from "../domain/languageDetect.js";
|
|
13
13
|
import { adaptRawStream, normalizeInterrupts } from "./streamAdapter.js";
|
|
14
14
|
function toLangchainMessages(messages) {
|
|
15
|
-
return messages.map((message) => message.
|
|
16
|
-
? new SystemMessage(message.content)
|
|
17
|
-
: new HumanMessage(message.content));
|
|
15
|
+
return messages.map((message) => new HumanMessage(message.content));
|
|
18
16
|
}
|
|
19
17
|
/**
|
|
20
18
|
* LangChain/LangGraph implementation of {@link LlmPort}. This is the single
|
|
@@ -34,6 +32,7 @@ export class LangGraphLlm {
|
|
|
34
32
|
: { messages: toLangchainMessages(input.input.messages) };
|
|
35
33
|
const rawStream = yield this.runtime.stream({
|
|
36
34
|
models,
|
|
35
|
+
systemPrompt: input.systemPrompt,
|
|
37
36
|
input: runtimeInput,
|
|
38
37
|
context: input.context,
|
|
39
38
|
observability: input.observability,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration shield for threads checkpointed before the system prompt moved out of the
|
|
3
|
+
* message history.
|
|
4
|
+
*
|
|
5
|
+
* Turns used to be started with `[SystemMessage, HumanMessage]`, so every such turn left
|
|
6
|
+
* a system message inside the thread's persisted state. Those messages are still in old
|
|
7
|
+
* checkpoints and would now arrive mid-history — both an invalid shape for providers that
|
|
8
|
+
* take the system prompt out-of-band, and a stale duplicate of a prompt the agent already
|
|
9
|
+
* supplies. So they are dropped, not re-hoisted: the authoritative prompt is
|
|
10
|
+
* `createAgent({ systemPrompt })` plus DynamicSystemPromptMiddleware.
|
|
11
|
+
*
|
|
12
|
+
* Nothing writes system messages into state any more, so for new threads this is a no-op.
|
|
13
|
+
* It stays as a cheap guard (and can be deleted once no pre-refactor checkpoints remain).
|
|
14
|
+
*/
|
|
15
|
+
export declare function createLegacySystemMessagesMiddleware(): import("langchain").AgentMiddleware<undefined, undefined, unknown, readonly (import("@langchain/core/tools").ClientTool | import("@langchain/core/tools").ServerTool)[]>;
|
|
@@ -0,0 +1,45 @@
|
|
|
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 { createMiddleware } from "langchain";
|
|
11
|
+
function isSystemMessage(message) {
|
|
12
|
+
var _a, _b;
|
|
13
|
+
return (((_a = message._getType) === null || _a === void 0 ? void 0 : _a.call(message)) === "system" ||
|
|
14
|
+
((_b = message.getType) === null || _b === void 0 ? void 0 : _b.call(message)) === "system" ||
|
|
15
|
+
message.type === "system");
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Migration shield for threads checkpointed before the system prompt moved out of the
|
|
19
|
+
* message history.
|
|
20
|
+
*
|
|
21
|
+
* Turns used to be started with `[SystemMessage, HumanMessage]`, so every such turn left
|
|
22
|
+
* a system message inside the thread's persisted state. Those messages are still in old
|
|
23
|
+
* checkpoints and would now arrive mid-history — both an invalid shape for providers that
|
|
24
|
+
* take the system prompt out-of-band, and a stale duplicate of a prompt the agent already
|
|
25
|
+
* supplies. So they are dropped, not re-hoisted: the authoritative prompt is
|
|
26
|
+
* `createAgent({ systemPrompt })` plus DynamicSystemPromptMiddleware.
|
|
27
|
+
*
|
|
28
|
+
* Nothing writes system messages into state any more, so for new threads this is a no-op.
|
|
29
|
+
* It stays as a cheap guard (and can be deleted once no pre-refactor checkpoints remain).
|
|
30
|
+
*/
|
|
31
|
+
export function createLegacySystemMessagesMiddleware() {
|
|
32
|
+
return createMiddleware({
|
|
33
|
+
name: "LegacySystemMessagesMiddleware",
|
|
34
|
+
wrapModelCall(request, handler) {
|
|
35
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
36
|
+
const typed = request;
|
|
37
|
+
const messages = typed.messages.filter((message) => !isSystemMessage(message));
|
|
38
|
+
if (messages.length === typed.messages.length) {
|
|
39
|
+
return handler(request);
|
|
40
|
+
}
|
|
41
|
+
return handler(Object.assign(Object.assign({}, request), { messages }));
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
@@ -7,6 +7,11 @@ export declare class AdminForthCheckpointSaver extends BaseCheckpointSaver {
|
|
|
7
7
|
constructor(adminforth: any, pluginOptions: PluginOptions);
|
|
8
8
|
private get resourceConfig();
|
|
9
9
|
private resource;
|
|
10
|
+
/**
|
|
11
|
+
* Checkpoints contain LangChain message instances. Plain JSON.stringify loses
|
|
12
|
+
* their constructors, so a resumed HITL middleware cannot recognize AIMessage
|
|
13
|
+
* tool calls. Use LangGraph's serializer, which preserves those constructors.
|
|
14
|
+
*/
|
|
10
15
|
private serialize;
|
|
11
16
|
private deserialize;
|
|
12
17
|
private now;
|
|
@@ -39,18 +39,28 @@ export class AdminForthCheckpointSaver extends BaseCheckpointSaver {
|
|
|
39
39
|
resource() {
|
|
40
40
|
return this.adminforth.resource(this.resourceConfig.resourceId);
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Checkpoints contain LangChain message instances. Plain JSON.stringify loses
|
|
44
|
+
* their constructors, so a resumed HITL middleware cannot recognize AIMessage
|
|
45
|
+
* tool calls. Use LangGraph's serializer, which preserves those constructors.
|
|
46
|
+
*/
|
|
42
47
|
serialize(value) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
49
|
+
if (value === undefined || value === null)
|
|
50
|
+
return null;
|
|
51
|
+
const [encoding, payload] = yield this.serde.dumpsTyped(value);
|
|
52
|
+
if (encoding !== "json") {
|
|
53
|
+
throw new Error(`Unsupported checkpoint payload encoding "${encoding}".`);
|
|
54
|
+
}
|
|
55
|
+
return new TextDecoder().decode(payload);
|
|
56
|
+
});
|
|
46
57
|
}
|
|
47
58
|
deserialize(value) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return JSON.
|
|
52
|
-
}
|
|
53
|
-
return value;
|
|
59
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
60
|
+
if (value === undefined || value === null)
|
|
61
|
+
return null;
|
|
62
|
+
return this.serde.loadsTyped("json", typeof value === "string" ? value : JSON.stringify(value));
|
|
63
|
+
});
|
|
54
64
|
}
|
|
55
65
|
now() {
|
|
56
66
|
return new Date().toISOString();
|
|
@@ -112,8 +122,8 @@ export class AdminForthCheckpointSaver extends BaseCheckpointSaver {
|
|
|
112
122
|
[r.taskIdField]: null,
|
|
113
123
|
[r.sequenceField]: 0,
|
|
114
124
|
[r.createdAtField]: createdAt,
|
|
115
|
-
[r.checkpointPayloadField]: this.serialize(checkpoint),
|
|
116
|
-
[r.metadataPayloadField]: this.serialize(metadata),
|
|
125
|
+
[r.checkpointPayloadField]: yield this.serialize(checkpoint),
|
|
126
|
+
[r.metadataPayloadField]: yield this.serialize(metadata),
|
|
117
127
|
[r.writesPayloadField]: null,
|
|
118
128
|
[r.schemaVersionField]: 1,
|
|
119
129
|
});
|
|
@@ -144,7 +154,7 @@ export class AdminForthCheckpointSaver extends BaseCheckpointSaver {
|
|
|
144
154
|
[r.createdAtField]: createdAt,
|
|
145
155
|
[r.checkpointPayloadField]: null,
|
|
146
156
|
[r.metadataPayloadField]: null,
|
|
147
|
-
[r.writesPayloadField]: this.serialize([channel, value]),
|
|
157
|
+
[r.writesPayloadField]: yield this.serialize([channel, value]),
|
|
148
158
|
[r.schemaVersionField]: 1,
|
|
149
159
|
});
|
|
150
160
|
}
|
|
@@ -171,23 +181,23 @@ export class AdminForthCheckpointSaver extends BaseCheckpointSaver {
|
|
|
171
181
|
}
|
|
172
182
|
const resolvedCheckpointId = String(checkpointRow[r.checkpointIdField]);
|
|
173
183
|
const writesRows = yield this.resource().list(Filters.AND(Filters.EQ(r.threadIdField, threadId), Filters.EQ(r.checkpointNamespaceField, storedCheckpointNs), Filters.EQ(r.checkpointIdField, resolvedCheckpointId), Filters.EQ(r.rowKindField, "writes")), undefined, undefined, [{ field: r.sequenceField, direction: "asc" }]);
|
|
174
|
-
const pendingWrites = writesRows.
|
|
184
|
+
const pendingWrites = (yield Promise.all(writesRows.map((row) => __awaiter(this, void 0, void 0, function* () {
|
|
175
185
|
var _a;
|
|
176
186
|
const taskId = String((_a = row[r.taskIdField]) !== null && _a !== void 0 ? _a : "");
|
|
177
|
-
const write = this.deserialize(row[r.writesPayloadField]);
|
|
187
|
+
const write = yield this.deserialize(row[r.writesPayloadField]);
|
|
178
188
|
if (!write) {
|
|
179
189
|
return [];
|
|
180
190
|
}
|
|
181
191
|
const [channel, value] = write;
|
|
182
192
|
return [[taskId, channel, value]];
|
|
183
|
-
});
|
|
193
|
+
})))).flat();
|
|
184
194
|
const parentCheckpointId = checkpointRow[r.parentCheckpointIdField]
|
|
185
195
|
? String(checkpointRow[r.parentCheckpointIdField])
|
|
186
196
|
: null;
|
|
187
197
|
const tuple = {
|
|
188
198
|
config: this.buildConfig(threadId, checkpointNs, resolvedCheckpointId),
|
|
189
|
-
checkpoint: this.deserialize(checkpointRow[r.checkpointPayloadField]),
|
|
190
|
-
metadata: ((_a = this.deserialize(checkpointRow[r.metadataPayloadField])) !== null && _a !== void 0 ? _a : {}),
|
|
199
|
+
checkpoint: yield this.deserialize(checkpointRow[r.checkpointPayloadField]),
|
|
200
|
+
metadata: ((_a = yield this.deserialize(checkpointRow[r.metadataPayloadField])) !== null && _a !== void 0 ? _a : {}),
|
|
191
201
|
parentConfig: parentCheckpointId
|
|
192
202
|
? this.buildConfig(threadId, checkpointNs, parentCheckpointId)
|
|
193
203
|
: undefined,
|
|
@@ -25,6 +25,7 @@ const agentResponseBodySchema = z.object({
|
|
|
25
25
|
const agentApprovalBodySchema = z.object({
|
|
26
26
|
sessionId: z.string(),
|
|
27
27
|
decision: z.enum(["approve", "reject"]),
|
|
28
|
+
mode: z.string().nullish(),
|
|
28
29
|
}).strict();
|
|
29
30
|
const agentSteerBodySchema = z.object({
|
|
30
31
|
sessionId: z.string(),
|
|
@@ -151,6 +152,7 @@ export function setupCoreEndpoints(ctx, server) {
|
|
|
151
152
|
yield ctx.handleTurn({
|
|
152
153
|
prompt: "",
|
|
153
154
|
sessionId: data.sessionId,
|
|
155
|
+
modeName: data.mode,
|
|
154
156
|
approvalDecision: data.decision,
|
|
155
157
|
abortSignal,
|
|
156
158
|
adminUser: adminUser,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adminforth/agent",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -44,11 +44,11 @@
|
|
|
44
44
|
"typescript": "^5.7.3"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@langchain/core": "
|
|
48
|
-
"@langchain/langgraph": "
|
|
49
|
-
"@langchain/langgraph-checkpoint": "
|
|
47
|
+
"@langchain/core": "1.2.5",
|
|
48
|
+
"@langchain/langgraph": "1.2.8",
|
|
49
|
+
"@langchain/langgraph-checkpoint": "1.0.1",
|
|
50
50
|
"dayjs": "^1.11.20",
|
|
51
|
-
"langchain": "
|
|
51
|
+
"langchain": "1.3.3",
|
|
52
52
|
"multer": "^2.1.1",
|
|
53
53
|
"vue-i18n": "^11.4.0",
|
|
54
54
|
"yaml": "^2.8.3",
|