@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.
- package/README.md +333 -10
- package/dist/application/ports.d.ts +66 -0
- package/dist/application/runTurnUseCase.d.ts +71 -0
- package/dist/application/runTurnUseCase.js +364 -0
- package/dist/custom/ChatFooter.vue +58 -30
- package/dist/custom/SteerDebugPanel.vue +45 -0
- package/dist/custom/SteerQueue.vue +54 -0
- package/dist/custom/composables/agentStore/constants.ts +1 -0
- package/dist/custom/composables/agentStore/useAgentSessions.ts +35 -16
- package/dist/custom/composables/agentStore/useAgentSteerQueue.ts +114 -0
- package/dist/custom/composables/useAgentStore.ts +46 -1
- package/dist/custom/conversation_area/MessageRenderer.vue +7 -1
- package/dist/custom/speech_recognition_frontend/AudioLines.vue +1 -1
- package/dist/custom/speech_recognition_frontend/MicrophoneButon.vue +3 -3
- package/dist/{agentEvents.d.ts → domain/agentEvents.d.ts} +5 -1
- package/dist/domain/steerBuffer.d.ts +33 -0
- package/dist/domain/steerBuffer.js +51 -0
- package/dist/{agent → domain}/systemPrompt.js +1 -1
- package/dist/{agent/turn → domain}/turnTypes.d.ts +41 -37
- package/dist/{agent/turn/VegaLiteStreamBuffer.d.ts → domain/vegaLiteStreamBuffer.d.ts} +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +49 -35
- package/dist/{agent/runtime/AgentContext.d.ts → llm/agentContext.d.ts} +3 -3
- package/dist/{agent/simpleAgent.d.ts → llm/agentModels.d.ts} +18 -16
- package/dist/llm/agentModels.js +65 -0
- package/dist/{agent/runtime/AgentRuntime.d.ts → llm/agentRuntime.d.ts} +14 -2
- package/dist/{agent/runtime/AgentRuntime.js → llm/agentRuntime.js} +41 -6
- package/dist/llm/langGraphLlm.d.ts +25 -0
- package/dist/llm/langGraphLlm.js +54 -0
- package/dist/{agent/middleware/apiBasedTools.d.ts → llm/middleware/apiToolsMiddleware.d.ts} +1 -1
- package/dist/{agent/middleware/apiBasedTools.js → llm/middleware/apiToolsMiddleware.js} +8 -14
- package/dist/{agent → llm}/middleware/sequenceDebug.d.ts +1 -1
- package/dist/llm/middleware/steerMiddleware.d.ts +21 -0
- package/dist/llm/middleware/steerMiddleware.js +50 -0
- package/dist/{agent/models/AgentModelFactory.d.ts → llm/modelFactory.d.ts} +1 -1
- package/dist/{agent/models/AgentModelFactory.js → llm/modelFactory.js} +1 -1
- package/dist/llm/streamAdapter.d.ts +18 -0
- package/dist/llm/streamAdapter.js +117 -0
- package/dist/{sessionStore.d.ts → persistence/sessionStore.d.ts} +19 -2
- package/dist/{sessionStore.js → persistence/sessionStore.js} +53 -0
- package/dist/{agent/tools/AgentToolProvider.d.ts → tools/agentToolProvider.d.ts} +1 -1
- package/dist/{agent/tools/AgentToolProvider.js → tools/agentToolProvider.js} +1 -1
- package/dist/{apiBasedTools.js → tools/apiBasedTools.js} +0 -3
- package/dist/{agent/tools → tools}/apiTool.d.ts +1 -1
- package/dist/{agent/tools → tools}/fetchSkill.js +1 -1
- package/dist/{agent/tools → tools}/fetchToolSchema.d.ts +1 -1
- package/dist/{agent/tools → tools}/index.d.ts +1 -1
- package/dist/{agent/tools → tools}/navigateUser.d.ts +3 -3
- package/dist/{endpoints → transport/http}/context.d.ts +12 -4
- package/dist/transport/http/context.js +1 -0
- package/dist/{endpoints/core.js → transport/http/coreEndpoints.js} +23 -3
- package/dist/{endpoints/sessions.js → transport/http/sessionEndpoints.js} +36 -1
- package/dist/transport/sse/sseWriter.d.ts +29 -0
- package/dist/{surfaces/web-sse/createSseEventEmitter.js → transport/sse/sseWriter.js} +27 -0
- package/dist/{chatSurfaceService.d.ts → transport/surfaces/chatSurfaceService.d.ts} +3 -3
- package/dist/{chatSurfaceService.js → transport/surfaces/chatSurfaceService.js} +7 -5
- package/dist/{agent/speech/SpeechTurnService.d.ts → transport/surfaces/speechTurnService.d.ts} +1 -1
- package/dist/{agent/speech/SpeechTurnService.js → transport/surfaces/speechTurnService.js} +2 -2
- package/dist/types.d.ts +10 -4
- package/package.json +11 -2
- package/.woodpecker/buildRelease.sh +0 -13
- package/.woodpecker/buildSlackNotify.sh +0 -46
- package/.woodpecker/release.yml +0 -57
- package/agent/checkpointer.ts +0 -329
- package/agent/languageDetect.ts +0 -92
- package/agent/middleware/apiBasedTools.ts +0 -174
- package/agent/middleware/openAiResponsesContinuation.ts +0 -92
- package/agent/middleware/sequenceDebug.ts +0 -429
- package/agent/models/AgentModeResolver.ts +0 -9
- package/agent/models/AgentModelFactory.ts +0 -28
- package/agent/runtime/AgentContext.ts +0 -30
- package/agent/runtime/AgentRuntime.ts +0 -89
- package/agent/simpleAgent.ts +0 -199
- package/agent/skills/registry.ts +0 -162
- package/agent/speech/SpeechTurnService.ts +0 -179
- package/agent/systemPrompt.ts +0 -133
- package/agent/toolCallEvents.ts +0 -135
- package/agent/tools/AgentToolProvider.ts +0 -28
- package/agent/tools/apiTool.ts +0 -66
- package/agent/tools/fetchSkill.ts +0 -68
- package/agent/tools/fetchToolSchema.ts +0 -47
- package/agent/tools/getUserLocation.ts +0 -45
- package/agent/tools/index.ts +0 -31
- package/agent/tools/navigateUser.ts +0 -210
- package/agent/turn/TurnContextBuilder.ts +0 -36
- package/agent/turn/TurnLifecycleService.ts +0 -47
- package/agent/turn/TurnPersistenceService.ts +0 -33
- package/agent/turn/TurnPromptBuilder.ts +0 -51
- package/agent/turn/TurnStreamConsumer.ts +0 -69
- package/agent/turn/VegaLiteStreamBuffer.ts +0 -90
- package/agent/turn/turnTypes.ts +0 -100
- package/agentEvents.ts +0 -75
- package/agentTurnService.ts +0 -314
- package/apiBasedTools.ts +0 -712
- package/build.log +0 -67
- package/chatSurfaceService.ts +0 -319
- package/custom/ChatFooter.vue +0 -173
- package/custom/ChatHeader.vue +0 -78
- package/custom/ChatSurface.vue +0 -160
- package/custom/CustomAutoScrollContainer.vue +0 -164
- package/custom/SessionsHistory.vue +0 -88
- package/custom/chat.ts +0 -82
- package/custom/composables/agentAudio/utils.ts +0 -220
- package/custom/composables/agentStore/constants.ts +0 -19
- package/custom/composables/agentStore/pageContext.ts +0 -8
- package/custom/composables/agentStore/useAgentChat.ts +0 -241
- package/custom/composables/agentStore/useAgentPlaceholder.ts +0 -142
- package/custom/composables/agentStore/useAgentSessions.ts +0 -350
- package/custom/composables/useAgentAudio.ts +0 -272
- package/custom/composables/useAgentStore.ts +0 -510
- package/custom/composables/useAgentTransitions.ts +0 -58
- package/custom/conversation_area/ConversationArea.vue +0 -301
- package/custom/conversation_area/MessageRenderer.vue +0 -49
- package/custom/conversation_area/ProcessingTimeline.vue +0 -286
- package/custom/conversation_area/ReasoningRenderer.vue +0 -79
- package/custom/conversation_area/SystemMessageRenderer.vue +0 -28
- package/custom/conversation_area/TextRenderer.vue +0 -182
- package/custom/conversation_area/ThreeDotsAnimation.vue +0 -35
- package/custom/conversation_area/ToolApprovalRenderer.vue +0 -98
- package/custom/conversation_area/ToolRenderer.vue +0 -178
- package/custom/conversation_area/ToolsGroup.vue +0 -59
- package/custom/env.d.ts +0 -7
- package/custom/incremark_code_renderers/IncremarkShikiCodeBlock.vue +0 -393
- package/custom/incremark_code_renderers/incremarkCodeHighlight.ts +0 -285
- package/custom/incremark_code_renderers/incremarkRenderer.ts +0 -653
- package/custom/incremark_code_renderers/renderIncremarkMarkdown.ts +0 -118
- package/custom/package.json +0 -30
- package/custom/pnpm-lock.yaml +0 -2394
- package/custom/public/agentAudio/agent-processing.mp3 +0 -0
- package/custom/skills/analyze_data/SKILL.md +0 -25
- package/custom/skills/charts/SKILL.md +0 -193
- package/custom/skills/fetch_data/SKILL.md +0 -31
- package/custom/skills/mutate_data/SKILL.md +0 -121
- package/custom/speech_recognition_frontend/AudioLines.vue +0 -43
- package/custom/speech_recognition_frontend/MicrophoneButon.vue +0 -185
- package/custom/speech_recognition_frontend/types/voice-activity-detection.d.ts +0 -22
- package/custom/speech_recognition_frontend/voiceActivityDetection.ts +0 -62
- package/custom/tsconfig.json +0 -15
- package/custom/types.ts +0 -108
- package/custom/utils.ts +0 -38
- package/dist/agent/middleware/openAiResponsesContinuation.d.ts +0 -1
- package/dist/agent/middleware/openAiResponsesContinuation.js +0 -66
- package/dist/agent/models/AgentModeResolver.d.ts +0 -9
- package/dist/agent/models/AgentModeResolver.js +0 -9
- package/dist/agent/simpleAgent.js +0 -118
- package/dist/agent/turn/TurnContextBuilder.d.ts +0 -14
- package/dist/agent/turn/TurnContextBuilder.js +0 -31
- package/dist/agent/turn/TurnLifecycleService.d.ts +0 -24
- package/dist/agent/turn/TurnLifecycleService.js +0 -47
- package/dist/agent/turn/TurnPersistenceService.d.ts +0 -13
- package/dist/agent/turn/TurnPersistenceService.js +0 -35
- package/dist/agent/turn/TurnPromptBuilder.d.ts +0 -19
- package/dist/agent/turn/TurnPromptBuilder.js +0 -43
- package/dist/agent/turn/TurnStreamConsumer.d.ts +0 -11
- package/dist/agent/turn/TurnStreamConsumer.js +0 -84
- package/dist/agentTurnService.d.ts +0 -24
- package/dist/agentTurnService.js +0 -269
- package/dist/surfaces/web-sse/createSseEventEmitter.d.ts +0 -14
- package/endpoints/chatSurfaces.ts +0 -66
- package/endpoints/context.ts +0 -52
- package/endpoints/core.ts +0 -181
- package/endpoints/sessions.ts +0 -183
- package/errors.ts +0 -10
- package/index.ts +0 -192
- package/pnpm-workspace.yaml +0 -4
- package/sanitizeSpeechText.ts +0 -32
- package/sessionStore.ts +0 -105
- package/surfaces/web-sse/createSseEventEmitter.ts +0 -311
- package/tsconfig.json +0 -14
- package/types.ts +0 -127
- /package/dist/{agent/turn/turnTypes.js → application/ports.js} +0 -0
- /package/dist/{agentEvents.js → domain/agentEvents.js} +0 -0
- /package/dist/{agent → domain}/languageDetect.d.ts +0 -0
- /package/dist/{agent → domain}/languageDetect.js +0 -0
- /package/dist/{agent → domain}/systemPrompt.d.ts +0 -0
- /package/dist/{agent → domain}/toolCallEvents.d.ts +0 -0
- /package/dist/{agent → domain}/toolCallEvents.js +0 -0
- /package/dist/{endpoints/context.js → domain/turnTypes.js} +0 -0
- /package/dist/{agent/turn/VegaLiteStreamBuffer.js → domain/vegaLiteStreamBuffer.js} +0 -0
- /package/dist/{agent/runtime/AgentContext.js → llm/agentContext.js} +0 -0
- /package/dist/{agent → llm}/middleware/sequenceDebug.js +0 -0
- /package/dist/{agent/checkpointer.d.ts → persistence/checkpointStore.d.ts} +0 -0
- /package/dist/{agent/checkpointer.js → persistence/checkpointStore.js} +0 -0
- /package/dist/{errors.d.ts → shared/errors.d.ts} +0 -0
- /package/dist/{errors.js → shared/errors.js} +0 -0
- /package/dist/{sanitizeSpeechText.d.ts → shared/sanitizeSpeechText.d.ts} +0 -0
- /package/dist/{sanitizeSpeechText.js → shared/sanitizeSpeechText.js} +0 -0
- /package/dist/{apiBasedTools.d.ts → tools/apiBasedTools.d.ts} +0 -0
- /package/dist/{agent/tools → tools}/apiTool.js +0 -0
- /package/dist/{agent/tools → tools}/fetchSkill.d.ts +0 -0
- /package/dist/{agent/tools → tools}/fetchToolSchema.js +0 -0
- /package/dist/{agent/tools → tools}/getUserLocation.d.ts +0 -0
- /package/dist/{agent/tools → tools}/getUserLocation.js +0 -0
- /package/dist/{agent/tools → tools}/index.js +0 -0
- /package/dist/{agent/tools → tools}/navigateUser.js +0 -0
- /package/dist/{agent → tools}/skills/registry.d.ts +0 -0
- /package/dist/{agent → tools}/skills/registry.js +0 -0
- /package/dist/{endpoints/chatSurfaces.d.ts → transport/http/chatSurfaceEndpoints.d.ts} +0 -0
- /package/dist/{endpoints/chatSurfaces.js → transport/http/chatSurfaceEndpoints.js} +0 -0
- /package/dist/{endpoints/core.d.ts → transport/http/coreEndpoints.d.ts} +0 -0
- /package/dist/{endpoints/sessions.d.ts → transport/http/sessionEndpoints.d.ts} +0 -0
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
import { tool } from "langchain";
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
import type { CurrentPageContext } from "./getUserLocation.js";
|
|
4
|
-
import type { AgentEventEmitter } from "../../agentEvents.js";
|
|
5
|
-
|
|
6
|
-
const filterSchema = z.object({
|
|
7
|
-
column: z.string().min(1).describe("Resource column name."),
|
|
8
|
-
operator: z
|
|
9
|
-
.string()
|
|
10
|
-
.min(1)
|
|
11
|
-
.describe("Filter operator suffix, for example eq, gte, lte, like, in."),
|
|
12
|
-
value: z.unknown().describe("Filter value. Dates should be ISO strings."),
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
const navigateUserSchema = z
|
|
16
|
-
.object({
|
|
17
|
-
targetPath: z
|
|
18
|
-
.string()
|
|
19
|
-
.optional()
|
|
20
|
-
.describe(
|
|
21
|
-
"Root-relative AdminForth path to open, with optional query string and hash, for example /resource/adminuser?sort=created_at__desc.",
|
|
22
|
-
),
|
|
23
|
-
resourceId: z
|
|
24
|
-
.string()
|
|
25
|
-
.optional()
|
|
26
|
-
.describe("Resource id to build an AdminForth resource route for."),
|
|
27
|
-
mode: z
|
|
28
|
-
.enum(["list", "show", "edit", "create"])
|
|
29
|
-
.optional()
|
|
30
|
-
.default("list")
|
|
31
|
-
.describe("Resource page mode. Defaults to list."),
|
|
32
|
-
recordId: z
|
|
33
|
-
.union([z.string(), z.number()])
|
|
34
|
-
.optional()
|
|
35
|
-
.describe("Record primary key for show or edit resource pages."),
|
|
36
|
-
filters: z
|
|
37
|
-
.array(filterSchema)
|
|
38
|
-
.optional()
|
|
39
|
-
.describe(
|
|
40
|
-
"List page filters. Each item becomes filter__{column}__{operator}=JSON.stringify(value).",
|
|
41
|
-
),
|
|
42
|
-
sort: z
|
|
43
|
-
.object({
|
|
44
|
-
column: z.string().min(1),
|
|
45
|
-
direction: z.enum(["asc", "desc"]),
|
|
46
|
-
})
|
|
47
|
-
.optional()
|
|
48
|
-
.describe("List page sort. Becomes sort={column}__{direction}."),
|
|
49
|
-
query: z
|
|
50
|
-
.record(z.string(), z.union([z.string(), z.number(), z.boolean()]))
|
|
51
|
-
.optional()
|
|
52
|
-
.describe("Additional query parameters to append to the target URL."),
|
|
53
|
-
})
|
|
54
|
-
.refine((input) => input.targetPath || input.resourceId, {
|
|
55
|
-
message: "Either targetPath or resourceId is required.",
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
function normalizeTargetPath(targetPath: string, currentPage?: CurrentPageContext) {
|
|
59
|
-
const trimmed = targetPath.trim();
|
|
60
|
-
|
|
61
|
-
if (!trimmed) {
|
|
62
|
-
throw new Error("targetPath cannot be empty.");
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const currentOrigin = currentPage?.url ? new URL(currentPage.url).origin : undefined;
|
|
66
|
-
|
|
67
|
-
if (currentOrigin) {
|
|
68
|
-
const targetUrl = new URL(trimmed, currentOrigin);
|
|
69
|
-
|
|
70
|
-
if (targetUrl.origin !== currentOrigin) {
|
|
71
|
-
throw new Error("Only same-origin navigation targets are allowed.");
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return `${targetUrl.pathname}${targetUrl.search}${targetUrl.hash}`;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const fallbackOrigin = "http://adminforth.local";
|
|
78
|
-
const targetUrl = new URL(trimmed, fallbackOrigin);
|
|
79
|
-
|
|
80
|
-
if (targetUrl.origin !== fallbackOrigin) {
|
|
81
|
-
throw new Error("Only relative AdminForth paths are allowed when current origin is unavailable.");
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return `${targetUrl.pathname}${targetUrl.search}${targetUrl.hash}`;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function appendQueryParams(path: string, params: URLSearchParams) {
|
|
88
|
-
const queryString = params.toString();
|
|
89
|
-
|
|
90
|
-
if (!queryString) {
|
|
91
|
-
return path;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const hashIndex = path.indexOf("#");
|
|
95
|
-
const pathWithoutHash = hashIndex === -1 ? path : path.slice(0, hashIndex);
|
|
96
|
-
const hash = hashIndex === -1 ? "" : path.slice(hashIndex);
|
|
97
|
-
const separator = pathWithoutHash.includes("?") ? "&" : "?";
|
|
98
|
-
|
|
99
|
-
return `${pathWithoutHash}${separator}${queryString}${hash}`;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function buildResourcePath(input: z.infer<typeof navigateUserSchema>) {
|
|
103
|
-
if (!input.resourceId) {
|
|
104
|
-
throw new Error("resourceId is required to build a resource route.");
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const resourceId = encodeURIComponent(input.resourceId);
|
|
108
|
-
const mode = input.mode ?? "list";
|
|
109
|
-
|
|
110
|
-
if (mode === "show" || mode === "edit") {
|
|
111
|
-
if (input.recordId === undefined || input.recordId === null) {
|
|
112
|
-
throw new Error(`recordId is required for ${mode} resource pages.`);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return `/resource/${resourceId}/${mode}/${encodeURIComponent(String(input.recordId))}`;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (mode === "create") {
|
|
119
|
-
return `/resource/${resourceId}/create`;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return `/resource/${resourceId}`;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function buildQueryParams(input: z.infer<typeof navigateUserSchema>) {
|
|
126
|
-
const params = new URLSearchParams();
|
|
127
|
-
|
|
128
|
-
for (const filter of input.filters ?? []) {
|
|
129
|
-
params.set(
|
|
130
|
-
`filter__${filter.column}__${filter.operator}`,
|
|
131
|
-
JSON.stringify(filter.value),
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (input.sort) {
|
|
136
|
-
params.set("sort", `${input.sort.column}__${input.sort.direction}`);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
for (const [key, value] of Object.entries(input.query ?? {})) {
|
|
140
|
-
params.set(key, String(value));
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return params;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function buildSurfaceUrl(targetPath: string, adminBaseUrl?: string, adminPublicOrigin?: string) {
|
|
147
|
-
const normalizedBasePath = adminBaseUrl?.replace(/\/+$/, "") ?? "";
|
|
148
|
-
const normalizedTargetPath = targetPath.replace(/^\/+/, "");
|
|
149
|
-
const path = `${normalizedBasePath}/${normalizedTargetPath}`;
|
|
150
|
-
|
|
151
|
-
return adminPublicOrigin ? new URL(path, adminPublicOrigin).toString() : path;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export function createNavigateUserTool() {
|
|
155
|
-
return tool(
|
|
156
|
-
async (input, runtime) => {
|
|
157
|
-
const context = runtime.context as {
|
|
158
|
-
currentPage?: CurrentPageContext;
|
|
159
|
-
chatSurface?: string;
|
|
160
|
-
adminBaseUrl?: string;
|
|
161
|
-
adminPublicOrigin?: string;
|
|
162
|
-
emit?: AgentEventEmitter;
|
|
163
|
-
};
|
|
164
|
-
const currentPage = context.currentPage;
|
|
165
|
-
const basePath = input.targetPath
|
|
166
|
-
? normalizeTargetPath(input.targetPath, currentPage)
|
|
167
|
-
: buildResourcePath(input);
|
|
168
|
-
const targetPath = appendQueryParams(basePath, buildQueryParams(input));
|
|
169
|
-
|
|
170
|
-
if (context.chatSurface) {
|
|
171
|
-
const url = buildSurfaceUrl(targetPath, context.adminBaseUrl, context.adminPublicOrigin);
|
|
172
|
-
|
|
173
|
-
return JSON.stringify(
|
|
174
|
-
{
|
|
175
|
-
status: 200,
|
|
176
|
-
action: "link",
|
|
177
|
-
surface: context.chatSurface,
|
|
178
|
-
targetPath,
|
|
179
|
-
url,
|
|
180
|
-
message: `Send this link to the user: ${url}`,
|
|
181
|
-
},
|
|
182
|
-
null,
|
|
183
|
-
2,
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
await context.emit?.({
|
|
188
|
-
type: "open-page",
|
|
189
|
-
targetPath,
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
return JSON.stringify(
|
|
193
|
-
{
|
|
194
|
-
status: 200,
|
|
195
|
-
action: "navigate",
|
|
196
|
-
targetPath,
|
|
197
|
-
message: `Navigation requested to ${targetPath}.`,
|
|
198
|
-
},
|
|
199
|
-
null,
|
|
200
|
-
2,
|
|
201
|
-
);
|
|
202
|
-
},
|
|
203
|
-
{
|
|
204
|
-
name: "navigate_user",
|
|
205
|
-
description:
|
|
206
|
-
"Navigate the user to another AdminForth page. Use this only when the user asks to open, show, go to, or switch to a resource list/detail page, including filtered or sorted resource lists. Or if the user is asked to open something on the left. Do not use this tool in any other case.",
|
|
207
|
-
schema: navigateUserSchema,
|
|
208
|
-
},
|
|
209
|
-
);
|
|
210
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import type { AdminUser, IAdminForth } from "adminforth";
|
|
2
|
-
import type { AgentTurnContext, BaseAgentTurnInput } from "./turnTypes.js";
|
|
3
|
-
|
|
4
|
-
export type UserContextProvider = {
|
|
5
|
-
getUserTimeZone(adminUser: AdminUser): Promise<string | null | undefined> | string | null | undefined;
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
export class TurnContextBuilder {
|
|
9
|
-
constructor(
|
|
10
|
-
private readonly getAdminforth: () => IAdminForth,
|
|
11
|
-
private readonly userContextProvider?: UserContextProvider,
|
|
12
|
-
) {}
|
|
13
|
-
|
|
14
|
-
async build(input: {
|
|
15
|
-
base: BaseAgentTurnInput;
|
|
16
|
-
turnId: string;
|
|
17
|
-
}): Promise<AgentTurnContext> {
|
|
18
|
-
const adminforth = this.getAdminforth();
|
|
19
|
-
|
|
20
|
-
return {
|
|
21
|
-
adminUser: input.base.adminUser,
|
|
22
|
-
sessionId: input.base.sessionId,
|
|
23
|
-
turnId: input.turnId,
|
|
24
|
-
abortSignal: input.base.abortSignal,
|
|
25
|
-
currentPage: input.base.currentPage,
|
|
26
|
-
chatSurface: input.base.chatSurface,
|
|
27
|
-
userTimeZone:
|
|
28
|
-
input.base.userTimeZone
|
|
29
|
-
?? await this.userContextProvider?.getUserTimeZone(input.base.adminUser)
|
|
30
|
-
?? "UTC",
|
|
31
|
-
adminPublicOrigin:
|
|
32
|
-
input.base.adminPublicOrigin
|
|
33
|
-
?? adminforth.config.baseUrlSlashed,
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import type { AgentSessionStore } from "../../sessionStore.js";
|
|
2
|
-
import type { PluginOptions } from "../../types.js";
|
|
3
|
-
import type { BaseAgentTurnInput } from "./turnTypes.js";
|
|
4
|
-
import { TurnPersistenceService } from "./TurnPersistenceService.js";
|
|
5
|
-
|
|
6
|
-
export class TurnLifecycleService {
|
|
7
|
-
constructor(
|
|
8
|
-
private readonly sessionStore: AgentSessionStore,
|
|
9
|
-
private readonly persistence: TurnPersistenceService,
|
|
10
|
-
private readonly options: PluginOptions,
|
|
11
|
-
) {}
|
|
12
|
-
|
|
13
|
-
async start(input: BaseAgentTurnInput) {
|
|
14
|
-
const previousUserMessages = await this.sessionStore.getPreviousUserMessages(input.sessionId);
|
|
15
|
-
const turnId = await this.sessionStore.createNewTurn(input.sessionId, input.prompt);
|
|
16
|
-
await this.persistence.touchSession(input.sessionId);
|
|
17
|
-
|
|
18
|
-
return {
|
|
19
|
-
turnId,
|
|
20
|
-
previousUserMessages,
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
async resume(input: BaseAgentTurnInput) {
|
|
25
|
-
const latestTurn = await this.sessionStore.getLatestTurn(input.sessionId);
|
|
26
|
-
|
|
27
|
-
if (!latestTurn) {
|
|
28
|
-
throw new Error(`No agent turn found for session "${input.sessionId}".`);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return {
|
|
32
|
-
turnId: latestTurn[this.options.turnResource.idField],
|
|
33
|
-
previousUserMessages: await this.sessionStore.getPreviousUserMessages(input.sessionId),
|
|
34
|
-
initialResponse: latestTurn[this.options.turnResource.responseField] === "not_finished"
|
|
35
|
-
? ""
|
|
36
|
-
: String(latestTurn[this.options.turnResource.responseField]),
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async finish(input: {
|
|
41
|
-
turnId: string;
|
|
42
|
-
responseText: string;
|
|
43
|
-
debugHistory?: unknown;
|
|
44
|
-
}) {
|
|
45
|
-
await this.persistence.saveTurnResponse(input);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import type { IAdminForth } from "adminforth";
|
|
2
|
-
import type { PluginOptions } from "../../types.js";
|
|
3
|
-
|
|
4
|
-
export class TurnPersistenceService {
|
|
5
|
-
constructor(
|
|
6
|
-
private readonly getAdminforth: () => IAdminForth,
|
|
7
|
-
private readonly options: PluginOptions,
|
|
8
|
-
) {}
|
|
9
|
-
|
|
10
|
-
async touchSession(sessionId: string) {
|
|
11
|
-
await this.getAdminforth().resource(this.options.sessionResource.resourceId).update(sessionId, {
|
|
12
|
-
[this.options.sessionResource.createdAtField]: new Date().toISOString(),
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
async saveTurnResponse(input: {
|
|
17
|
-
turnId: string;
|
|
18
|
-
responseText: string;
|
|
19
|
-
debugHistory?: unknown;
|
|
20
|
-
}) {
|
|
21
|
-
const turnUpdates: Record<string, unknown> = {
|
|
22
|
-
[this.options.turnResource.responseField]: input.responseText,
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
if (this.options.turnResource.debugField) {
|
|
26
|
-
turnUpdates[this.options.turnResource.debugField] = input.debugHistory;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
await this.getAdminforth()
|
|
30
|
-
.resource(this.options.turnResource.resourceId)
|
|
31
|
-
.update(input.turnId, turnUpdates);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import type { AdminUser, IAdminForth } from "adminforth";
|
|
2
|
-
import { logger } from "adminforth";
|
|
3
|
-
import { HumanMessage, SystemMessage } from "langchain";
|
|
4
|
-
import { detectUserLanguage, type PreviousUserMessage } from "../languageDetect.js";
|
|
5
|
-
import { buildAgentTurnSystemPrompt } from "../systemPrompt.js";
|
|
6
|
-
import { getErrorMessage, isAbortError } from "../../errors.js";
|
|
7
|
-
import type { AgentModeCompletionAdapter } from "../simpleAgent.js";
|
|
8
|
-
|
|
9
|
-
export class TurnPromptBuilder {
|
|
10
|
-
constructor(
|
|
11
|
-
private readonly options: {
|
|
12
|
-
getAgentSystemPrompt: () => Promise<string>;
|
|
13
|
-
getAdminforth: () => IAdminForth;
|
|
14
|
-
},
|
|
15
|
-
) {}
|
|
16
|
-
|
|
17
|
-
async build(input: {
|
|
18
|
-
prompt: string;
|
|
19
|
-
previousUserMessages: PreviousUserMessage[];
|
|
20
|
-
adminUser: AdminUser;
|
|
21
|
-
completionAdapter: AgentModeCompletionAdapter;
|
|
22
|
-
chatSurface?: string;
|
|
23
|
-
abortSignal?: AbortSignal;
|
|
24
|
-
}) {
|
|
25
|
-
const adminforth = this.options.getAdminforth();
|
|
26
|
-
const userLanguage = await detectUserLanguage(
|
|
27
|
-
input.completionAdapter,
|
|
28
|
-
input.prompt,
|
|
29
|
-
input.previousUserMessages,
|
|
30
|
-
).catch((error) => {
|
|
31
|
-
if (input.abortSignal?.aborted || isAbortError(error)) {
|
|
32
|
-
throw error;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
logger.warn(`Failed to detect user language: ${getErrorMessage(error)}`);
|
|
36
|
-
return null;
|
|
37
|
-
});
|
|
38
|
-
const systemPrompt = buildAgentTurnSystemPrompt({
|
|
39
|
-
agentSystemPrompt: await this.options.getAgentSystemPrompt(),
|
|
40
|
-
adminUser: input.adminUser,
|
|
41
|
-
usernameField: adminforth.config.auth!.usernameField,
|
|
42
|
-
userLanguage,
|
|
43
|
-
chatSurface: input.chatSurface,
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
return [
|
|
47
|
-
new SystemMessage(systemPrompt),
|
|
48
|
-
new HumanMessage(input.prompt),
|
|
49
|
-
];
|
|
50
|
-
}
|
|
51
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import type { AgentEventEmitter } from "../../agentEvents.js";
|
|
2
|
-
import { VegaLiteStreamBuffer } from "./VegaLiteStreamBuffer.js";
|
|
3
|
-
|
|
4
|
-
export class TurnStreamConsumer {
|
|
5
|
-
async consume(input: {
|
|
6
|
-
stream: AsyncIterable<["messages", [any, any]] | ["updates", Record<string, any>]>;
|
|
7
|
-
abortSignal?: AbortSignal;
|
|
8
|
-
emit?: AgentEventEmitter;
|
|
9
|
-
onInterrupt?: (interrupt: unknown) => void | Promise<void>;
|
|
10
|
-
}) {
|
|
11
|
-
let fullResponse = "";
|
|
12
|
-
const textBuffer = new VegaLiteStreamBuffer();
|
|
13
|
-
|
|
14
|
-
for await (const [mode, chunk] of input.stream) {
|
|
15
|
-
if (input.abortSignal?.aborted) {
|
|
16
|
-
throw new DOMException("This operation was aborted", "AbortError");
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (mode === "updates") {
|
|
20
|
-
if ("__interrupt__" in chunk) {
|
|
21
|
-
await input.onInterrupt?.(chunk.__interrupt__);
|
|
22
|
-
}
|
|
23
|
-
continue;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const [token, metadata] = chunk;
|
|
27
|
-
const nodeName =
|
|
28
|
-
typeof metadata?.langgraph_node === "string"
|
|
29
|
-
? metadata.langgraph_node
|
|
30
|
-
: "";
|
|
31
|
-
|
|
32
|
-
if (nodeName && !["model", "model_request"].includes(nodeName)) {
|
|
33
|
-
continue;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const blocks = Array.isArray(token?.contentBlocks)
|
|
37
|
-
? token.contentBlocks
|
|
38
|
-
: Array.isArray(token?.content)
|
|
39
|
-
? token.content
|
|
40
|
-
: [];
|
|
41
|
-
const reasoningDelta = blocks
|
|
42
|
-
.filter((block: any) => block?.type === "reasoning")
|
|
43
|
-
.map((block: any) => String(block.reasoning ?? ""))
|
|
44
|
-
.join("");
|
|
45
|
-
const textDelta = blocks
|
|
46
|
-
.filter((block: any) => block?.type === "text")
|
|
47
|
-
.map((block: any) => String(block.text ?? ""))
|
|
48
|
-
.join("");
|
|
49
|
-
|
|
50
|
-
if (reasoningDelta) {
|
|
51
|
-
await input.emit?.({
|
|
52
|
-
type: "reasoning-delta",
|
|
53
|
-
delta: reasoningDelta,
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (textDelta) {
|
|
58
|
-
fullResponse += textDelta;
|
|
59
|
-
await textBuffer.push(textDelta, input.emit);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
await textBuffer.flush(input.emit);
|
|
64
|
-
|
|
65
|
-
return {
|
|
66
|
-
text: fullResponse,
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import type { AgentEventEmitter } from "../../agentEvents.js";
|
|
2
|
-
|
|
3
|
-
const VEGA_LITE_FENCE_START = "```vega-lite";
|
|
4
|
-
const FENCE_END = "```";
|
|
5
|
-
|
|
6
|
-
export class VegaLiteStreamBuffer {
|
|
7
|
-
private bufferedTextDelta = "";
|
|
8
|
-
private isRenderingVegaLite = false;
|
|
9
|
-
|
|
10
|
-
async push(textDelta: string, emit?: AgentEventEmitter) {
|
|
11
|
-
this.bufferedTextDelta += textDelta;
|
|
12
|
-
|
|
13
|
-
if (
|
|
14
|
-
hasUnclosedLatestVegaLiteBlock(this.bufferedTextDelta)
|
|
15
|
-
) {
|
|
16
|
-
if (!this.isRenderingVegaLite) {
|
|
17
|
-
this.isRenderingVegaLite = true;
|
|
18
|
-
await emit?.({
|
|
19
|
-
type: "rendering",
|
|
20
|
-
phase: "start",
|
|
21
|
-
label: "Rendering...",
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if (this.isRenderingVegaLite) {
|
|
28
|
-
this.isRenderingVegaLite = false;
|
|
29
|
-
await emit?.({
|
|
30
|
-
type: "rendering",
|
|
31
|
-
phase: "end",
|
|
32
|
-
label: "Rendering...",
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const streamableLength = this.bufferedTextDelta.includes(VEGA_LITE_FENCE_START)
|
|
37
|
-
? this.bufferedTextDelta.length
|
|
38
|
-
: this.bufferedTextDelta.length - getPartialVegaLiteFenceStartLength(this.bufferedTextDelta);
|
|
39
|
-
|
|
40
|
-
if (!streamableLength) {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
await emit?.({
|
|
45
|
-
type: "text-delta",
|
|
46
|
-
delta: this.bufferedTextDelta.slice(0, streamableLength),
|
|
47
|
-
});
|
|
48
|
-
this.bufferedTextDelta = this.bufferedTextDelta.slice(streamableLength);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async flush(emit?: AgentEventEmitter) {
|
|
52
|
-
if (this.isRenderingVegaLite) {
|
|
53
|
-
await emit?.({
|
|
54
|
-
type: "rendering",
|
|
55
|
-
phase: "end",
|
|
56
|
-
label: "Rendering...",
|
|
57
|
-
});
|
|
58
|
-
this.isRenderingVegaLite = false;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (this.bufferedTextDelta) {
|
|
62
|
-
await emit?.({
|
|
63
|
-
type: "text-delta",
|
|
64
|
-
delta: this.bufferedTextDelta,
|
|
65
|
-
});
|
|
66
|
-
this.bufferedTextDelta = "";
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function hasUnclosedLatestVegaLiteBlock(text: string): boolean {
|
|
72
|
-
const latestBlockStart = text.lastIndexOf(VEGA_LITE_FENCE_START);
|
|
73
|
-
|
|
74
|
-
if (latestBlockStart === -1) {
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const blockContentStart = latestBlockStart + VEGA_LITE_FENCE_START.length;
|
|
79
|
-
return text.indexOf(FENCE_END, blockContentStart) === -1;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function getPartialVegaLiteFenceStartLength(text: string): number {
|
|
83
|
-
for (let length = Math.min(text.length, VEGA_LITE_FENCE_START.length - 1); length > 0; length -= 1) {
|
|
84
|
-
if (VEGA_LITE_FENCE_START.startsWith(text.slice(-length))) {
|
|
85
|
-
return length;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return 0;
|
|
90
|
-
}
|
package/agent/turn/turnTypes.ts
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import type { AdminUser, AudioAdapter } from "adminforth";
|
|
2
|
-
import type { Messages } from "@langchain/langgraph";
|
|
3
|
-
import type { Command } from "@langchain/langgraph";
|
|
4
|
-
import type { AgentChatModel, AgentMiddleware } from "../simpleAgent.js";
|
|
5
|
-
import type { SequenceDebugCollector } from "../middleware/sequenceDebug.js";
|
|
6
|
-
import type { PreviousUserMessage } from "../languageDetect.js";
|
|
7
|
-
import type { CurrentPageContext } from "../tools/getUserLocation.js";
|
|
8
|
-
import type { AgentEventEmitter } from "../../agentEvents.js";
|
|
9
|
-
|
|
10
|
-
export type BaseAgentTurnInput = {
|
|
11
|
-
prompt: string;
|
|
12
|
-
sessionId: string;
|
|
13
|
-
modeName?: string | null;
|
|
14
|
-
userTimeZone?: string;
|
|
15
|
-
currentPage?: CurrentPageContext;
|
|
16
|
-
chatSurface?: string;
|
|
17
|
-
adminPublicOrigin?: string;
|
|
18
|
-
abortSignal?: AbortSignal;
|
|
19
|
-
adminUser: AdminUser;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export type TextAgentTurnInput = BaseAgentTurnInput & {
|
|
23
|
-
emit: AgentEventEmitter;
|
|
24
|
-
approvalDecision?: "approve" | "reject";
|
|
25
|
-
failureLogMessage?: string;
|
|
26
|
-
abortLogMessage?: string;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export type SpeechAgentTurnInput = Omit<BaseAgentTurnInput, "prompt"> & {
|
|
30
|
-
emit: AgentEventEmitter;
|
|
31
|
-
audioAdapter: AudioAdapter;
|
|
32
|
-
audio: {
|
|
33
|
-
buffer: Buffer;
|
|
34
|
-
filename: string;
|
|
35
|
-
mimeType: string;
|
|
36
|
-
};
|
|
37
|
-
failureLogMessage?: string;
|
|
38
|
-
abortLogMessage?: string;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export type AgentTurnContext = {
|
|
42
|
-
adminUser: AdminUser;
|
|
43
|
-
userTimeZone: string;
|
|
44
|
-
sessionId: string;
|
|
45
|
-
turnId: string;
|
|
46
|
-
abortSignal?: AbortSignal;
|
|
47
|
-
currentPage?: CurrentPageContext;
|
|
48
|
-
chatSurface?: string;
|
|
49
|
-
adminPublicOrigin?: string;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
export type AgentTurnObservability = {
|
|
53
|
-
emit?: AgentEventEmitter;
|
|
54
|
-
sequenceDebugSink: SequenceDebugCollector;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
export type PreparedAgentTurn = {
|
|
58
|
-
prompt: string;
|
|
59
|
-
sessionId: string;
|
|
60
|
-
turnId: string;
|
|
61
|
-
previousUserMessages: PreviousUserMessage[];
|
|
62
|
-
modeName?: string | null;
|
|
63
|
-
context: AgentTurnContext;
|
|
64
|
-
observability: AgentTurnObservability;
|
|
65
|
-
resume?: {
|
|
66
|
-
decision: "approve" | "reject";
|
|
67
|
-
interrupts?: { id: string; count: number }[];
|
|
68
|
-
};
|
|
69
|
-
initialResponse?: string;
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
export type AgentTurnModels = {
|
|
73
|
-
model: AgentChatModel;
|
|
74
|
-
summaryModel: AgentChatModel;
|
|
75
|
-
modelMiddleware?: AgentMiddleware[];
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
export type AgentRuntimeRunInput = {
|
|
79
|
-
models: AgentTurnModels;
|
|
80
|
-
input: { messages: Messages } | Command;
|
|
81
|
-
context: AgentTurnContext;
|
|
82
|
-
observability: AgentTurnObservability;
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
export type RunAndPersistAgentResponseInput = BaseAgentTurnInput & {
|
|
86
|
-
emit?: AgentEventEmitter;
|
|
87
|
-
approvalDecision?: "approve" | "reject";
|
|
88
|
-
failureLogMessage: string;
|
|
89
|
-
abortLogMessage: string;
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
export type RunAndPersistAgentResponseResult = {
|
|
93
|
-
text: string;
|
|
94
|
-
turnId: string;
|
|
95
|
-
aborted: boolean;
|
|
96
|
-
failed: boolean;
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
export type HandleTurnInput = TextAgentTurnInput;
|
|
100
|
-
export type HandleSpeechTurnInput = SpeechAgentTurnInput;
|