@adminforth/agent 1.50.0 → 1.51.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/agent/middleware/apiBasedTools.ts +13 -3
- package/agent/models/AgentModeResolver.ts +9 -0
- package/agent/models/AgentModelFactory.ts +28 -0
- package/agent/runtime/AgentContext.ts +30 -0
- package/agent/runtime/AgentRuntime.ts +68 -0
- package/agent/simpleAgent.ts +2 -129
- package/agent/speech/SpeechTurnService.ts +179 -0
- package/agent/tools/AgentToolProvider.ts +28 -0
- package/agent/tools/navigateUser.ts +2 -2
- package/agent/turn/TurnContextBuilder.ts +36 -0
- package/agent/turn/TurnLifecycleService.ts +29 -0
- package/agent/turn/TurnPersistenceService.ts +33 -0
- package/agent/turn/TurnPromptBuilder.ts +51 -0
- package/agent/turn/TurnStreamConsumer.ts +61 -0
- package/agent/turn/VegaLiteStreamBuffer.ts +90 -0
- package/agent/turn/turnTypes.ts +92 -0
- package/agentTurnService.ts +88 -461
- package/build.log +2 -2
- package/custom/skills/fetch_data/SKILL.md +2 -0
- package/custom/skills/mutate_data/SKILL.md +4 -0
- package/dist/agent/middleware/apiBasedTools.js +9 -2
- package/dist/agent/models/AgentModeResolver.d.ts +9 -0
- package/dist/agent/models/AgentModeResolver.js +9 -0
- package/dist/agent/models/AgentModelFactory.d.ts +7 -0
- package/dist/agent/models/AgentModelFactory.js +36 -0
- package/dist/agent/runtime/AgentContext.d.ts +28 -0
- package/dist/agent/runtime/AgentContext.js +17 -0
- package/dist/agent/runtime/AgentRuntime.d.ts +15 -0
- package/dist/agent/runtime/AgentRuntime.js +57 -0
- package/dist/agent/simpleAgent.d.ts +15 -45
- package/dist/agent/simpleAgent.js +1 -67
- package/dist/agent/speech/SpeechTurnService.d.ts +6 -0
- package/dist/agent/speech/SpeechTurnService.js +168 -0
- package/dist/agent/tools/AgentToolProvider.d.ts +9 -0
- package/dist/agent/tools/AgentToolProvider.js +27 -0
- package/dist/agent/tools/navigateUser.js +1 -1
- package/dist/agent/turn/TurnContextBuilder.d.ts +14 -0
- package/dist/agent/turn/TurnContextBuilder.js +31 -0
- package/dist/agent/turn/TurnLifecycleService.d.ts +17 -0
- package/dist/agent/turn/TurnLifecycleService.js +31 -0
- package/dist/agent/turn/TurnPersistenceService.d.ts +13 -0
- package/dist/agent/turn/TurnPersistenceService.js +35 -0
- package/dist/agent/turn/TurnPromptBuilder.d.ts +19 -0
- package/dist/agent/turn/TurnPromptBuilder.js +43 -0
- package/dist/agent/turn/TurnStreamConsumer.d.ts +10 -0
- package/dist/agent/turn/TurnStreamConsumer.js +78 -0
- package/dist/agent/turn/VegaLiteStreamBuffer.d.ts +7 -0
- package/dist/agent/turn/VegaLiteStreamBuffer.js +87 -0
- package/dist/agent/turn/turnTypes.d.ts +81 -0
- package/dist/agent/turn/turnTypes.js +1 -0
- package/dist/agentTurnService.d.ts +20 -69
- package/dist/agentTurnService.js +60 -373
- package/dist/custom/skills/fetch_data/SKILL.md +2 -0
- package/dist/custom/skills/mutate_data/SKILL.md +4 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +22 -7
- package/index.ts +35 -7
- package/package.json +1 -1
package/dist/agentTurnService.js
CHANGED
|
@@ -7,231 +7,79 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
11
|
-
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
12
|
-
var m = o[Symbol.asyncIterator], i;
|
|
13
|
-
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
14
|
-
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
15
|
-
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
16
|
-
};
|
|
17
10
|
import { logger } from "adminforth";
|
|
18
11
|
import { randomUUID } from "crypto";
|
|
19
|
-
import { HumanMessage, SystemMessage } from "langchain";
|
|
20
|
-
import { createAgentChatModel, callAgent } from "./agent/simpleAgent.js";
|
|
21
12
|
import { createSequenceDebugCollector } from "./agent/middleware/sequenceDebug.js";
|
|
22
|
-
import {
|
|
23
|
-
import { prepareApiBasedTools as buildApiBasedTools } from "./apiBasedTools.js";
|
|
24
|
-
import { buildAgentTurnSystemPrompt } from "./agent/systemPrompt.js";
|
|
25
|
-
import { isAbortError, getErrorMessage } from "./errors.js";
|
|
26
|
-
import { sanitizeSpeechText } from "./sanitizeSpeechText.js";
|
|
27
|
-
const VEGA_LITE_FENCE_START = "```vega-lite";
|
|
28
|
-
const COMPLETE_VEGA_LITE_BLOCK_RE = /```vega-lite[\s\S]*?```/;
|
|
13
|
+
import { getErrorMessage, isAbortError } from "./errors.js";
|
|
29
14
|
export class AgentTurnService {
|
|
30
|
-
constructor(
|
|
31
|
-
this.
|
|
15
|
+
constructor(lifecycle, contextBuilder, modeResolver, modelFactory, promptBuilder, runtime, streamConsumer) {
|
|
16
|
+
this.lifecycle = lifecycle;
|
|
17
|
+
this.contextBuilder = contextBuilder;
|
|
18
|
+
this.modeResolver = modeResolver;
|
|
19
|
+
this.modelFactory = modelFactory;
|
|
20
|
+
this.promptBuilder = promptBuilder;
|
|
21
|
+
this.runtime = runtime;
|
|
22
|
+
this.streamConsumer = streamConsumer;
|
|
23
|
+
}
|
|
24
|
+
prepareTurn(input) {
|
|
25
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
26
|
+
const sequenceDebugCollector = createSequenceDebugCollector();
|
|
27
|
+
const { turnId, previousUserMessages } = yield this.lifecycle.start(input);
|
|
28
|
+
const context = yield this.contextBuilder.build({
|
|
29
|
+
base: input,
|
|
30
|
+
turnId,
|
|
31
|
+
});
|
|
32
|
+
return {
|
|
33
|
+
prompt: input.prompt,
|
|
34
|
+
sessionId: input.sessionId,
|
|
35
|
+
turnId,
|
|
36
|
+
previousUserMessages,
|
|
37
|
+
modeName: input.modeName,
|
|
38
|
+
context,
|
|
39
|
+
observability: {
|
|
40
|
+
emit: undefined,
|
|
41
|
+
sequenceDebugSink: sequenceDebugCollector,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
});
|
|
32
45
|
}
|
|
33
46
|
runAgentTurn(input) {
|
|
34
47
|
return __awaiter(this, void 0, void 0, function* () {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
createAgentChatModel({
|
|
46
|
-
adapter: selectedMode.completionAdapter,
|
|
47
|
-
maxTokens,
|
|
48
|
-
purpose: "primary",
|
|
49
|
-
}),
|
|
50
|
-
createAgentChatModel({
|
|
51
|
-
adapter: selectedMode.completionAdapter,
|
|
52
|
-
maxTokens,
|
|
53
|
-
purpose: "summary",
|
|
48
|
+
const selectedMode = this.modeResolver.resolve(input.modeName);
|
|
49
|
+
const [models, messages] = yield Promise.all([
|
|
50
|
+
this.modelFactory.create(selectedMode.completionAdapter),
|
|
51
|
+
this.promptBuilder.build({
|
|
52
|
+
prompt: input.prompt,
|
|
53
|
+
previousUserMessages: input.previousUserMessages,
|
|
54
|
+
adminUser: input.context.adminUser,
|
|
55
|
+
completionAdapter: selectedMode.completionAdapter,
|
|
56
|
+
chatSurface: input.context.chatSurface,
|
|
57
|
+
abortSignal: input.context.abortSignal,
|
|
54
58
|
}),
|
|
55
59
|
]);
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
.
|
|
61
|
-
var _a;
|
|
62
|
-
if (((_a = input.abortSignal) === null || _a === void 0 ? void 0 : _a.aborted) || isAbortError(error)) {
|
|
63
|
-
throw error;
|
|
64
|
-
}
|
|
65
|
-
logger.warn(`Failed to detect user language: ${getErrorMessage(error)}`);
|
|
66
|
-
return null;
|
|
60
|
+
const stream = yield this.runtime.stream({
|
|
61
|
+
models,
|
|
62
|
+
messages,
|
|
63
|
+
context: input.context,
|
|
64
|
+
observability: input.observability,
|
|
67
65
|
});
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
userLanguage,
|
|
73
|
-
chatSurface: input.chatSurface,
|
|
66
|
+
return this.streamConsumer.consume({
|
|
67
|
+
stream: stream,
|
|
68
|
+
abortSignal: input.context.abortSignal,
|
|
69
|
+
emit: input.observability.emit,
|
|
74
70
|
});
|
|
75
|
-
const apiBasedTools = buildApiBasedTools(adminforth, this.serviceOptions.getInternalAgentResourceIds());
|
|
76
|
-
const stream = yield callAgent({
|
|
77
|
-
name: `adminforth-agent-${this.serviceOptions.getPluginInstanceId()}`,
|
|
78
|
-
model,
|
|
79
|
-
summaryModel,
|
|
80
|
-
modelMiddleware,
|
|
81
|
-
checkpointer: this.serviceOptions.getCheckpointer(),
|
|
82
|
-
messages: [
|
|
83
|
-
new SystemMessage(systemPrompt),
|
|
84
|
-
new HumanMessage(input.prompt),
|
|
85
|
-
],
|
|
86
|
-
adminUser: input.adminUser,
|
|
87
|
-
adminforth,
|
|
88
|
-
apiBasedTools,
|
|
89
|
-
customComponentsDir: (_f = adminforth.config.customization.customComponentsDir) !== null && _f !== void 0 ? _f : "custom",
|
|
90
|
-
pluginCustomFolderPaths: adminforth.activatedPlugins.map((plugin) => plugin.customFolderPath),
|
|
91
|
-
sessionId: input.sessionId,
|
|
92
|
-
turnId: input.turnId,
|
|
93
|
-
currentPage: input.currentPage,
|
|
94
|
-
chatSurface: input.chatSurface,
|
|
95
|
-
adminPublicOrigin: input.adminPublicOrigin,
|
|
96
|
-
userTimeZone: input.userTimeZone,
|
|
97
|
-
abortSignal: input.abortSignal,
|
|
98
|
-
emitToolCallEvent: (event) => {
|
|
99
|
-
var _a;
|
|
100
|
-
input.sequenceDebugCollector.handleToolCallEvent(event);
|
|
101
|
-
void ((_a = input.emit) === null || _a === void 0 ? void 0 : _a.call(input, {
|
|
102
|
-
type: "tool-call",
|
|
103
|
-
data: event,
|
|
104
|
-
}));
|
|
105
|
-
},
|
|
106
|
-
emitAgentEvent: input.emit,
|
|
107
|
-
sequenceDebugSink: input.sequenceDebugCollector,
|
|
108
|
-
});
|
|
109
|
-
try {
|
|
110
|
-
for (var _p = true, _q = __asyncValues(stream), _r; _r = yield _q.next(), _a = _r.done, !_a; _p = true) {
|
|
111
|
-
_c = _r.value;
|
|
112
|
-
_p = false;
|
|
113
|
-
const rawChunk = _c;
|
|
114
|
-
if ((_g = input.abortSignal) === null || _g === void 0 ? void 0 : _g.aborted) {
|
|
115
|
-
throw new DOMException("This operation was aborted", "AbortError");
|
|
116
|
-
}
|
|
117
|
-
const [token, metadata] = rawChunk;
|
|
118
|
-
const nodeName = typeof (metadata === null || metadata === void 0 ? void 0 : metadata.langgraph_node) === "string"
|
|
119
|
-
? metadata.langgraph_node
|
|
120
|
-
: "";
|
|
121
|
-
if (nodeName && !["model", "model_request"].includes(nodeName)) {
|
|
122
|
-
continue;
|
|
123
|
-
}
|
|
124
|
-
const blocks = Array.isArray(token === null || token === void 0 ? void 0 : token.contentBlocks)
|
|
125
|
-
? token.contentBlocks
|
|
126
|
-
: Array.isArray(token === null || token === void 0 ? void 0 : token.content)
|
|
127
|
-
? token.content
|
|
128
|
-
: [];
|
|
129
|
-
const reasoningDelta = blocks
|
|
130
|
-
.filter((b) => (b === null || b === void 0 ? void 0 : b.type) === "reasoning")
|
|
131
|
-
.map((b) => { var _a; return String((_a = b.reasoning) !== null && _a !== void 0 ? _a : ""); })
|
|
132
|
-
.join("");
|
|
133
|
-
const textDelta = blocks
|
|
134
|
-
.filter((b) => (b === null || b === void 0 ? void 0 : b.type) === "text")
|
|
135
|
-
.map((b) => { var _a; return String((_a = b.text) !== null && _a !== void 0 ? _a : ""); })
|
|
136
|
-
.join("");
|
|
137
|
-
if (reasoningDelta) {
|
|
138
|
-
yield ((_h = input.emit) === null || _h === void 0 ? void 0 : _h.call(input, {
|
|
139
|
-
type: "reasoning-delta",
|
|
140
|
-
delta: reasoningDelta,
|
|
141
|
-
}));
|
|
142
|
-
}
|
|
143
|
-
if (textDelta) {
|
|
144
|
-
fullResponse += textDelta;
|
|
145
|
-
bufferedTextDelta += textDelta;
|
|
146
|
-
if (bufferedTextDelta.includes(VEGA_LITE_FENCE_START) &&
|
|
147
|
-
!COMPLETE_VEGA_LITE_BLOCK_RE.test(bufferedTextDelta)) {
|
|
148
|
-
if (!isRenderingVegaLite) {
|
|
149
|
-
isRenderingVegaLite = true;
|
|
150
|
-
yield ((_j = input.emit) === null || _j === void 0 ? void 0 : _j.call(input, {
|
|
151
|
-
type: "rendering",
|
|
152
|
-
phase: "start",
|
|
153
|
-
label: "Rendering...",
|
|
154
|
-
}));
|
|
155
|
-
}
|
|
156
|
-
continue;
|
|
157
|
-
}
|
|
158
|
-
if (isRenderingVegaLite) {
|
|
159
|
-
isRenderingVegaLite = false;
|
|
160
|
-
yield ((_k = input.emit) === null || _k === void 0 ? void 0 : _k.call(input, {
|
|
161
|
-
type: "rendering",
|
|
162
|
-
phase: "end",
|
|
163
|
-
label: "Rendering...",
|
|
164
|
-
}));
|
|
165
|
-
}
|
|
166
|
-
const streamableLength = bufferedTextDelta.includes(VEGA_LITE_FENCE_START)
|
|
167
|
-
? bufferedTextDelta.length
|
|
168
|
-
: bufferedTextDelta.length - getPartialVegaLiteFenceStartLength(bufferedTextDelta);
|
|
169
|
-
if (!streamableLength) {
|
|
170
|
-
continue;
|
|
171
|
-
}
|
|
172
|
-
yield ((_l = input.emit) === null || _l === void 0 ? void 0 : _l.call(input, {
|
|
173
|
-
type: "text-delta",
|
|
174
|
-
delta: bufferedTextDelta.slice(0, streamableLength),
|
|
175
|
-
}));
|
|
176
|
-
bufferedTextDelta = bufferedTextDelta.slice(streamableLength);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
181
|
-
finally {
|
|
182
|
-
try {
|
|
183
|
-
if (!_p && !_a && (_b = _q.return)) yield _b.call(_q);
|
|
184
|
-
}
|
|
185
|
-
finally { if (e_1) throw e_1.error; }
|
|
186
|
-
}
|
|
187
|
-
if (isRenderingVegaLite) {
|
|
188
|
-
yield ((_m = input.emit) === null || _m === void 0 ? void 0 : _m.call(input, {
|
|
189
|
-
type: "rendering",
|
|
190
|
-
phase: "end",
|
|
191
|
-
label: "Rendering...",
|
|
192
|
-
}));
|
|
193
|
-
}
|
|
194
|
-
if (bufferedTextDelta) {
|
|
195
|
-
yield ((_o = input.emit) === null || _o === void 0 ? void 0 : _o.call(input, {
|
|
196
|
-
type: "text-delta",
|
|
197
|
-
delta: bufferedTextDelta,
|
|
198
|
-
}));
|
|
199
|
-
}
|
|
200
|
-
return {
|
|
201
|
-
text: fullResponse,
|
|
202
|
-
};
|
|
203
71
|
});
|
|
204
72
|
}
|
|
205
73
|
runAndPersistAgentResponse(input) {
|
|
206
74
|
return __awaiter(this, void 0, void 0, function* () {
|
|
207
75
|
var _a;
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
const previousUserMessages = yield this.serviceOptions.sessionStore.getPreviousUserMessages(input.sessionId);
|
|
211
|
-
const turnId = yield this.serviceOptions.sessionStore.createNewTurn(input.sessionId, input.prompt);
|
|
212
|
-
yield adminforth.resource(options.sessionResource.resourceId).update(input.sessionId, {
|
|
213
|
-
[options.sessionResource.createdAtField]: new Date().toISOString(),
|
|
214
|
-
});
|
|
215
|
-
const sequenceDebugCollector = createSequenceDebugCollector();
|
|
76
|
+
const preparedTurn = yield this.prepareTurn(input);
|
|
77
|
+
preparedTurn.observability.emit = input.emit;
|
|
216
78
|
let fullResponse = "";
|
|
217
79
|
let aborted = false;
|
|
218
80
|
let failed = false;
|
|
219
81
|
try {
|
|
220
|
-
const agentResponse = yield this.runAgentTurn(
|
|
221
|
-
prompt: input.prompt,
|
|
222
|
-
sessionId: input.sessionId,
|
|
223
|
-
turnId,
|
|
224
|
-
previousUserMessages,
|
|
225
|
-
modeName: input.modeName,
|
|
226
|
-
userTimeZone: input.userTimeZone,
|
|
227
|
-
currentPage: input.currentPage,
|
|
228
|
-
chatSurface: input.chatSurface,
|
|
229
|
-
adminPublicOrigin: input.adminPublicOrigin,
|
|
230
|
-
abortSignal: input.abortSignal,
|
|
231
|
-
adminUser: input.adminUser,
|
|
232
|
-
sequenceDebugCollector,
|
|
233
|
-
emit: input.emit,
|
|
234
|
-
});
|
|
82
|
+
const agentResponse = yield this.runAgentTurn(preparedTurn);
|
|
235
83
|
fullResponse = agentResponse.text;
|
|
236
84
|
}
|
|
237
85
|
catch (error) {
|
|
@@ -245,17 +93,15 @@ export class AgentTurnService {
|
|
|
245
93
|
logger.error(`${input.failureLogMessage}:\n${fullResponse}`);
|
|
246
94
|
}
|
|
247
95
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
}
|
|
255
|
-
yield adminforth.resource(options.turnResource.resourceId).update(turnId, turnUpdates);
|
|
96
|
+
preparedTurn.observability.sequenceDebugSink.flush();
|
|
97
|
+
yield this.lifecycle.finish({
|
|
98
|
+
turnId: preparedTurn.turnId,
|
|
99
|
+
responseText: fullResponse,
|
|
100
|
+
debugHistory: preparedTurn.observability.sequenceDebugSink.getHistory(),
|
|
101
|
+
});
|
|
256
102
|
return {
|
|
257
103
|
text: fullResponse,
|
|
258
|
-
turnId,
|
|
104
|
+
turnId: preparedTurn.turnId,
|
|
259
105
|
aborted,
|
|
260
106
|
failed,
|
|
261
107
|
};
|
|
@@ -302,163 +148,4 @@ export class AgentTurnService {
|
|
|
302
148
|
return agentResponse;
|
|
303
149
|
});
|
|
304
150
|
}
|
|
305
|
-
handleSpeechTurn(input) {
|
|
306
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
307
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
308
|
-
let transcription;
|
|
309
|
-
try {
|
|
310
|
-
transcription = yield input.audioAdapter.transcribe({
|
|
311
|
-
buffer: input.audio.buffer,
|
|
312
|
-
filename: input.audio.filename,
|
|
313
|
-
mimeType: input.audio.mimeType,
|
|
314
|
-
language: "auto",
|
|
315
|
-
abortSignal: input.abortSignal,
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
catch (error) {
|
|
319
|
-
if (((_a = input.abortSignal) === null || _a === void 0 ? void 0 : _a.aborted) || isAbortError(error)) {
|
|
320
|
-
logger.info("Agent speech transcription aborted by the client");
|
|
321
|
-
yield input.emit({ type: "finish" });
|
|
322
|
-
return null;
|
|
323
|
-
}
|
|
324
|
-
logger.error(`Agent speech transcription failed:\n${getErrorMessage(error)}`);
|
|
325
|
-
yield input.emit({
|
|
326
|
-
type: "error",
|
|
327
|
-
error: "Speech transcription failed. Check server logs for details.",
|
|
328
|
-
});
|
|
329
|
-
yield input.emit({ type: "finish" });
|
|
330
|
-
return null;
|
|
331
|
-
}
|
|
332
|
-
if ((_b = input.abortSignal) === null || _b === void 0 ? void 0 : _b.aborted) {
|
|
333
|
-
yield input.emit({ type: "finish" });
|
|
334
|
-
return null;
|
|
335
|
-
}
|
|
336
|
-
const prompt = transcription.text;
|
|
337
|
-
if (!prompt) {
|
|
338
|
-
yield input.emit({
|
|
339
|
-
type: "error",
|
|
340
|
-
error: "Speech transcription is empty",
|
|
341
|
-
});
|
|
342
|
-
yield input.emit({ type: "finish" });
|
|
343
|
-
return null;
|
|
344
|
-
}
|
|
345
|
-
yield input.emit({
|
|
346
|
-
type: "transcript",
|
|
347
|
-
text: transcription.text,
|
|
348
|
-
language: transcription.language,
|
|
349
|
-
});
|
|
350
|
-
const agentResponse = yield this.runAndPersistAgentResponse({
|
|
351
|
-
prompt,
|
|
352
|
-
sessionId: input.sessionId,
|
|
353
|
-
modeName: input.modeName,
|
|
354
|
-
userTimeZone: input.userTimeZone,
|
|
355
|
-
currentPage: input.currentPage,
|
|
356
|
-
chatSurface: input.chatSurface,
|
|
357
|
-
adminPublicOrigin: input.adminPublicOrigin,
|
|
358
|
-
abortSignal: input.abortSignal,
|
|
359
|
-
adminUser: input.adminUser,
|
|
360
|
-
emit: (event) => __awaiter(this, void 0, void 0, function* () {
|
|
361
|
-
if (event.type === "tool-call") {
|
|
362
|
-
yield input.emit(event);
|
|
363
|
-
}
|
|
364
|
-
}),
|
|
365
|
-
failureLogMessage: (_c = input.failureLogMessage) !== null && _c !== void 0 ? _c : "Agent speech response failed",
|
|
366
|
-
abortLogMessage: (_d = input.abortLogMessage) !== null && _d !== void 0 ? _d : "Agent speech response aborted by the client",
|
|
367
|
-
});
|
|
368
|
-
if (agentResponse.aborted) {
|
|
369
|
-
yield input.emit({ type: "finish" });
|
|
370
|
-
return agentResponse;
|
|
371
|
-
}
|
|
372
|
-
if (agentResponse.failed) {
|
|
373
|
-
yield input.emit({
|
|
374
|
-
type: "error",
|
|
375
|
-
error: agentResponse.text,
|
|
376
|
-
});
|
|
377
|
-
yield input.emit({ type: "finish" });
|
|
378
|
-
return agentResponse;
|
|
379
|
-
}
|
|
380
|
-
try {
|
|
381
|
-
yield input.emit({
|
|
382
|
-
type: "speech-response",
|
|
383
|
-
transcript: {
|
|
384
|
-
text: transcription.text,
|
|
385
|
-
language: transcription.language,
|
|
386
|
-
},
|
|
387
|
-
response: {
|
|
388
|
-
text: agentResponse.text,
|
|
389
|
-
},
|
|
390
|
-
sessionId: input.sessionId,
|
|
391
|
-
turnId: agentResponse.turnId,
|
|
392
|
-
});
|
|
393
|
-
const speech = yield input.audioAdapter.synthesize({
|
|
394
|
-
text: sanitizeSpeechText(agentResponse.text),
|
|
395
|
-
stream: true,
|
|
396
|
-
streamFormat: "audio",
|
|
397
|
-
format: "pcm",
|
|
398
|
-
abortSignal: input.abortSignal,
|
|
399
|
-
});
|
|
400
|
-
yield input.emit({
|
|
401
|
-
type: "audio-start",
|
|
402
|
-
mimeType: speech.mimeType,
|
|
403
|
-
format: speech.format,
|
|
404
|
-
sampleRate: 24000,
|
|
405
|
-
channelCount: 1,
|
|
406
|
-
bitsPerSample: 16,
|
|
407
|
-
});
|
|
408
|
-
const reader = speech.audioStream.getReader();
|
|
409
|
-
const cancelAudioStream = () => {
|
|
410
|
-
void reader.cancel().catch(() => undefined);
|
|
411
|
-
};
|
|
412
|
-
try {
|
|
413
|
-
(_e = input.abortSignal) === null || _e === void 0 ? void 0 : _e.addEventListener("abort", cancelAudioStream, { once: true });
|
|
414
|
-
while (true) {
|
|
415
|
-
if ((_f = input.abortSignal) === null || _f === void 0 ? void 0 : _f.aborted) {
|
|
416
|
-
yield reader.cancel().catch(() => undefined);
|
|
417
|
-
break;
|
|
418
|
-
}
|
|
419
|
-
const { value, done } = yield reader.read();
|
|
420
|
-
if (done) {
|
|
421
|
-
break;
|
|
422
|
-
}
|
|
423
|
-
if ((_g = input.abortSignal) === null || _g === void 0 ? void 0 : _g.aborted) {
|
|
424
|
-
break;
|
|
425
|
-
}
|
|
426
|
-
yield input.emit({
|
|
427
|
-
type: "audio-delta",
|
|
428
|
-
value,
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
finally {
|
|
433
|
-
(_h = input.abortSignal) === null || _h === void 0 ? void 0 : _h.removeEventListener("abort", cancelAudioStream);
|
|
434
|
-
reader.releaseLock();
|
|
435
|
-
}
|
|
436
|
-
yield input.emit({ type: "audio-done" });
|
|
437
|
-
yield input.emit({ type: "finish" });
|
|
438
|
-
return agentResponse;
|
|
439
|
-
}
|
|
440
|
-
catch (error) {
|
|
441
|
-
if (((_j = input.abortSignal) === null || _j === void 0 ? void 0 : _j.aborted) || isAbortError(error)) {
|
|
442
|
-
logger.info("Agent speech audio streaming aborted by the client");
|
|
443
|
-
}
|
|
444
|
-
else {
|
|
445
|
-
logger.error(`Agent speech audio streaming failed:\n${getErrorMessage(error)}`);
|
|
446
|
-
yield input.emit({
|
|
447
|
-
type: "error",
|
|
448
|
-
error: getErrorMessage(error),
|
|
449
|
-
});
|
|
450
|
-
}
|
|
451
|
-
yield input.emit({ type: "finish" });
|
|
452
|
-
return agentResponse;
|
|
453
|
-
}
|
|
454
|
-
});
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
function getPartialVegaLiteFenceStartLength(text) {
|
|
458
|
-
for (let length = Math.min(text.length, VEGA_LITE_FENCE_START.length - 1); length > 0; length -= 1) {
|
|
459
|
-
if (VEGA_LITE_FENCE_START.startsWith(text.slice(-length))) {
|
|
460
|
-
return length;
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
return 0;
|
|
464
151
|
}
|
|
@@ -24,6 +24,8 @@ If several rows look similar, do not guess which one is "the same" record. Show
|
|
|
24
24
|
|
|
25
25
|
For long texts show only several first words and add "..." at the end (only if user did not request this field specifically).
|
|
26
26
|
|
|
27
|
+
Never show information about more than 10 records in one message. If a tool returns more than 10 relevant records, summarize the total count if known, show only the 10 most relevant records, and offer to narrow filters, sort differently, or continue with the next 10.
|
|
28
|
+
|
|
27
29
|
Also when you communicate with user about record, add related link to this record. Build it as `{ADMIN_BASE_PATH}resource/{resourceId}/show/{primary key}`. Use _label from `get_resource_data` as anchor text for link (use markdown link). Links should always be relative paths and must start with `ADMIN_BASE_PATH`. Do not add an extra slash after `ADMIN_BASE_PATH`.
|
|
28
30
|
|
|
29
31
|
Before sending the link, verify that the `resourceId`, `{primary key}`, `_label`, and shown fields come from the same exact returned row.
|
|
@@ -27,6 +27,8 @@ Also please add related link to record with will be changed. Build it as `{ADMIN
|
|
|
27
27
|
|
|
28
28
|
Before sending the confirmation, verify that the `resourceId`, `{primary key}`, `_label`, and all shown fields come from the same exact fetched row.
|
|
29
29
|
|
|
30
|
+
Never show information about more than 10 records in one message. If a mutation plan affects more than 10 records, show only the 10 most important examples plus the total count if known, and ask the user to confirm the clearly described full batch.
|
|
31
|
+
|
|
30
32
|
And in the same message ask user for final confirmation.
|
|
31
33
|
|
|
32
34
|
When creating new record, show user all data which you gona create and in same message ask for confirmation.
|
|
@@ -123,6 +125,8 @@ For decimal fields please use string values with dot as decimal separator.
|
|
|
123
125
|
|
|
124
126
|
After creation of new record also show user a link to this record. If several records record were created, show links to all of them in list.
|
|
125
127
|
|
|
128
|
+
If more than 10 records were created, show links or details for only 10 of them and summarize the remaining count.
|
|
129
|
+
|
|
126
130
|
Omit any pictures or file paths, you are not capable of doing it. If they are not required all is good, if they are required, explain to user that you are not able to create record because of this reason.
|
|
127
131
|
|
|
128
132
|
### Working with dates
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -17,6 +17,16 @@ import { setupChatSurfaceEndpoints } from "./endpoints/chatSurfaces.js";
|
|
|
17
17
|
import { AgentSessionStore } from "./sessionStore.js";
|
|
18
18
|
import { ChatSurfaceService } from "./chatSurfaceService.js";
|
|
19
19
|
import { AgentTurnService } from "./agentTurnService.js";
|
|
20
|
+
import { AgentModelFactory } from "./agent/models/AgentModelFactory.js";
|
|
21
|
+
import { AgentModeResolver } from "./agent/models/AgentModeResolver.js";
|
|
22
|
+
import { AgentRuntime } from "./agent/runtime/AgentRuntime.js";
|
|
23
|
+
import { SpeechTurnService } from "./agent/speech/SpeechTurnService.js";
|
|
24
|
+
import { AgentToolProvider } from "./agent/tools/AgentToolProvider.js";
|
|
25
|
+
import { TurnContextBuilder } from "./agent/turn/TurnContextBuilder.js";
|
|
26
|
+
import { TurnLifecycleService } from "./agent/turn/TurnLifecycleService.js";
|
|
27
|
+
import { TurnPersistenceService } from "./agent/turn/TurnPersistenceService.js";
|
|
28
|
+
import { TurnPromptBuilder } from "./agent/turn/TurnPromptBuilder.js";
|
|
29
|
+
import { TurnStreamConsumer } from "./agent/turn/TurnStreamConsumer.js";
|
|
20
30
|
export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
21
31
|
parseBody(schema, body, response) {
|
|
22
32
|
const parsed = schema.safeParse(body !== null && body !== void 0 ? body : {});
|
|
@@ -43,19 +53,24 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
43
53
|
].filter((resourceId) => Boolean(resourceId));
|
|
44
54
|
}
|
|
45
55
|
constructor(options) {
|
|
56
|
+
var _a;
|
|
46
57
|
super(options, import.meta.url);
|
|
47
58
|
this.checkpointer = null;
|
|
48
59
|
this.options = options;
|
|
49
60
|
this.sessionStore = new AgentSessionStore(() => this.adminforth, this.options);
|
|
50
|
-
|
|
61
|
+
const toolProvider = new AgentToolProvider(() => this.adminforth, this.getInternalAgentResourceIds.bind(this));
|
|
62
|
+
const runtime = new AgentRuntime({
|
|
63
|
+
name: `adminforth-agent-${this.pluginInstanceId}`,
|
|
51
64
|
getAdminforth: () => this.adminforth,
|
|
52
|
-
getPluginInstanceId: () => this.pluginInstanceId,
|
|
53
|
-
options: this.options,
|
|
54
|
-
sessionStore: this.sessionStore,
|
|
55
65
|
getCheckpointer: this.getCheckpointer.bind(this),
|
|
56
|
-
|
|
57
|
-
getAgentSystemPrompt: () => this.agentSystemPromptPromise,
|
|
66
|
+
toolProvider,
|
|
58
67
|
});
|
|
68
|
+
const persistence = new TurnPersistenceService(() => this.adminforth, this.options);
|
|
69
|
+
this.agentTurnService = new AgentTurnService(new TurnLifecycleService(this.sessionStore, persistence), new TurnContextBuilder(() => this.adminforth), new AgentModeResolver(this.options), new AgentModelFactory((_a = this.options.maxTokens) !== null && _a !== void 0 ? _a : 1000), new TurnPromptBuilder({
|
|
70
|
+
getAdminforth: () => this.adminforth,
|
|
71
|
+
getAgentSystemPrompt: () => this.agentSystemPromptPromise,
|
|
72
|
+
}), runtime, new TurnStreamConsumer());
|
|
73
|
+
this.speechTurnService = new SpeechTurnService(this.agentTurnService.runAndPersistAgentResponse.bind(this.agentTurnService));
|
|
59
74
|
this.chatSurfaceService = new ChatSurfaceService(() => this.adminforth, this.options, this.sessionStore, this.agentTurnService.handleTurn.bind(this.agentTurnService), this.agentTurnService.runAndPersistAgentResponse.bind(this.agentTurnService));
|
|
60
75
|
this.agentSystemPromptPromise = Promise.resolve(appendCustomSystemPrompt(DEFAULT_AGENT_SYSTEM_PROMPT, this.options.systemPrompt));
|
|
61
76
|
this.shouldHaveSingleInstancePerWholeApp = () => false;
|
|
@@ -120,7 +135,7 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
120
135
|
options: this.options,
|
|
121
136
|
parseBody: this.parseBody.bind(this),
|
|
122
137
|
handleTurn: this.agentTurnService.handleTurn.bind(this.agentTurnService),
|
|
123
|
-
handleSpeechTurn: this.
|
|
138
|
+
handleSpeechTurn: this.speechTurnService.handle.bind(this.speechTurnService),
|
|
124
139
|
runAndPersistAgentResponse: this.agentTurnService.runAndPersistAgentResponse.bind(this.agentTurnService),
|
|
125
140
|
getSessionTurns: this.sessionStore.getSessionTurns.bind(this.sessionStore),
|
|
126
141
|
createNewTurn: this.sessionStore.createNewTurn.bind(this.sessionStore),
|
package/index.ts
CHANGED
|
@@ -18,6 +18,16 @@ import type { AgentEndpointsContext } from "./endpoints/context.js";
|
|
|
18
18
|
import { AgentSessionStore } from "./sessionStore.js";
|
|
19
19
|
import { ChatSurfaceService } from "./chatSurfaceService.js";
|
|
20
20
|
import { AgentTurnService } from "./agentTurnService.js";
|
|
21
|
+
import { AgentModelFactory } from "./agent/models/AgentModelFactory.js";
|
|
22
|
+
import { AgentModeResolver } from "./agent/models/AgentModeResolver.js";
|
|
23
|
+
import { AgentRuntime } from "./agent/runtime/AgentRuntime.js";
|
|
24
|
+
import { SpeechTurnService } from "./agent/speech/SpeechTurnService.js";
|
|
25
|
+
import { AgentToolProvider } from "./agent/tools/AgentToolProvider.js";
|
|
26
|
+
import { TurnContextBuilder } from "./agent/turn/TurnContextBuilder.js";
|
|
27
|
+
import { TurnLifecycleService } from "./agent/turn/TurnLifecycleService.js";
|
|
28
|
+
import { TurnPersistenceService } from "./agent/turn/TurnPersistenceService.js";
|
|
29
|
+
import { TurnPromptBuilder } from "./agent/turn/TurnPromptBuilder.js";
|
|
30
|
+
import { TurnStreamConsumer } from "./agent/turn/TurnStreamConsumer.js";
|
|
21
31
|
|
|
22
32
|
export type { AgentEvent, AgentEventEmitter } from "./agentEvents.js";
|
|
23
33
|
|
|
@@ -27,6 +37,7 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
27
37
|
private checkpointer: BaseCheckpointSaver | null = null;
|
|
28
38
|
private sessionStore: AgentSessionStore;
|
|
29
39
|
private agentTurnService: AgentTurnService;
|
|
40
|
+
private speechTurnService: SpeechTurnService;
|
|
30
41
|
private chatSurfaceService: ChatSurfaceService;
|
|
31
42
|
private parseBody<T>(
|
|
32
43
|
schema: z.ZodType<T>,
|
|
@@ -62,15 +73,32 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
62
73
|
super(options, import.meta.url);
|
|
63
74
|
this.options = options;
|
|
64
75
|
this.sessionStore = new AgentSessionStore(() => this.adminforth, this.options);
|
|
65
|
-
|
|
76
|
+
const toolProvider = new AgentToolProvider(
|
|
77
|
+
() => this.adminforth,
|
|
78
|
+
this.getInternalAgentResourceIds.bind(this),
|
|
79
|
+
);
|
|
80
|
+
const runtime = new AgentRuntime({
|
|
81
|
+
name: `adminforth-agent-${this.pluginInstanceId}`,
|
|
66
82
|
getAdminforth: () => this.adminforth,
|
|
67
|
-
getPluginInstanceId: () => this.pluginInstanceId,
|
|
68
|
-
options: this.options,
|
|
69
|
-
sessionStore: this.sessionStore,
|
|
70
83
|
getCheckpointer: this.getCheckpointer.bind(this),
|
|
71
|
-
|
|
72
|
-
getAgentSystemPrompt: () => this.agentSystemPromptPromise,
|
|
84
|
+
toolProvider,
|
|
73
85
|
});
|
|
86
|
+
const persistence = new TurnPersistenceService(() => this.adminforth, this.options);
|
|
87
|
+
this.agentTurnService = new AgentTurnService(
|
|
88
|
+
new TurnLifecycleService(this.sessionStore, persistence),
|
|
89
|
+
new TurnContextBuilder(() => this.adminforth),
|
|
90
|
+
new AgentModeResolver(this.options),
|
|
91
|
+
new AgentModelFactory(this.options.maxTokens ?? 1000),
|
|
92
|
+
new TurnPromptBuilder({
|
|
93
|
+
getAdminforth: () => this.adminforth,
|
|
94
|
+
getAgentSystemPrompt: () => this.agentSystemPromptPromise,
|
|
95
|
+
}),
|
|
96
|
+
runtime,
|
|
97
|
+
new TurnStreamConsumer(),
|
|
98
|
+
);
|
|
99
|
+
this.speechTurnService = new SpeechTurnService(
|
|
100
|
+
this.agentTurnService.runAndPersistAgentResponse.bind(this.agentTurnService),
|
|
101
|
+
);
|
|
74
102
|
this.chatSurfaceService = new ChatSurfaceService(
|
|
75
103
|
() => this.adminforth,
|
|
76
104
|
this.options,
|
|
@@ -146,7 +174,7 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
146
174
|
options: this.options,
|
|
147
175
|
parseBody: this.parseBody.bind(this),
|
|
148
176
|
handleTurn: this.agentTurnService.handleTurn.bind(this.agentTurnService),
|
|
149
|
-
handleSpeechTurn: this.
|
|
177
|
+
handleSpeechTurn: this.speechTurnService.handle.bind(this.speechTurnService),
|
|
150
178
|
runAndPersistAgentResponse: this.agentTurnService.runAndPersistAgentResponse.bind(this.agentTurnService),
|
|
151
179
|
getSessionTurns: this.sessionStore.getSessionTurns.bind(this.sessionStore),
|
|
152
180
|
createNewTurn: this.sessionStore.createNewTurn.bind(this.sessionStore),
|