@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
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
2
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
3
|
+
var m = o[Symbol.asyncIterator], i;
|
|
4
|
+
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);
|
|
5
|
+
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); }); }; }
|
|
6
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
7
|
+
};
|
|
8
|
+
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
|
|
9
|
+
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
|
|
10
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
11
|
+
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
12
|
+
return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
|
|
13
|
+
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
|
|
14
|
+
function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
|
|
15
|
+
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
|
|
16
|
+
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
|
17
|
+
function fulfill(value) { resume("next", value); }
|
|
18
|
+
function reject(value) { resume("throw", value); }
|
|
19
|
+
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
|
|
20
|
+
};
|
|
21
|
+
// Only tokens emitted by the model node(s) are surfaced to the user; other
|
|
22
|
+
// graph nodes (tools, summarization, etc.) are internal.
|
|
23
|
+
const STREAMABLE_NODES = ["model", "model_request"];
|
|
24
|
+
function getInterruptItems(interrupt) {
|
|
25
|
+
return Array.isArray(interrupt) ? interrupt : [interrupt];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Normalize raw LangGraph interrupt object(s) into provider-agnostic descriptors.
|
|
29
|
+
* Kept in the llm layer so the LangGraph interrupt shape never reaches the app.
|
|
30
|
+
*/
|
|
31
|
+
export function normalizeInterrupts(interrupt) {
|
|
32
|
+
return getInterruptItems(interrupt).flatMap((item) => {
|
|
33
|
+
const value = item && typeof item === "object" && "value" in item
|
|
34
|
+
? item.value
|
|
35
|
+
: item;
|
|
36
|
+
const actionRequests = value && typeof value === "object"
|
|
37
|
+
? value.actionRequests
|
|
38
|
+
: undefined;
|
|
39
|
+
const interruptId = item && typeof item === "object"
|
|
40
|
+
? item.id
|
|
41
|
+
: undefined;
|
|
42
|
+
return typeof interruptId === "string" && Array.isArray(actionRequests)
|
|
43
|
+
? [{ id: interruptId, count: actionRequests.length }]
|
|
44
|
+
: [];
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function extractBlocks(token) {
|
|
48
|
+
if (Array.isArray(token === null || token === void 0 ? void 0 : token.contentBlocks)) {
|
|
49
|
+
return token.contentBlocks;
|
|
50
|
+
}
|
|
51
|
+
if (Array.isArray(token === null || token === void 0 ? void 0 : token.content)) {
|
|
52
|
+
return token.content;
|
|
53
|
+
}
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Convert one raw LangGraph stream entry into zero or more normalized chunks.
|
|
58
|
+
* Pure and synchronous so the parsing rules can be unit-tested in isolation.
|
|
59
|
+
*/
|
|
60
|
+
export function parseRawStreamChunk(entry) {
|
|
61
|
+
const [mode, chunk] = entry;
|
|
62
|
+
if (mode === "updates") {
|
|
63
|
+
if (chunk && typeof chunk === "object" && "__interrupt__" in chunk) {
|
|
64
|
+
const interrupt = chunk.__interrupt__;
|
|
65
|
+
return [{ kind: "interrupt", interrupt, descriptors: normalizeInterrupts(interrupt) }];
|
|
66
|
+
}
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
const [token, metadata] = chunk;
|
|
70
|
+
const nodeName = typeof (metadata === null || metadata === void 0 ? void 0 : metadata.langgraph_node) === "string" ? metadata.langgraph_node : "";
|
|
71
|
+
if (nodeName && !STREAMABLE_NODES.includes(nodeName)) {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
const blocks = extractBlocks(token);
|
|
75
|
+
const chunks = [];
|
|
76
|
+
const reasoning = blocks
|
|
77
|
+
.filter((block) => (block === null || block === void 0 ? void 0 : block.type) === "reasoning")
|
|
78
|
+
.map((block) => { var _a; return String((_a = block.reasoning) !== null && _a !== void 0 ? _a : ""); })
|
|
79
|
+
.join("");
|
|
80
|
+
const text = blocks
|
|
81
|
+
.filter((block) => (block === null || block === void 0 ? void 0 : block.type) === "text")
|
|
82
|
+
.map((block) => { var _a; return String((_a = block.text) !== null && _a !== void 0 ? _a : ""); })
|
|
83
|
+
.join("");
|
|
84
|
+
if (reasoning) {
|
|
85
|
+
chunks.push({ kind: "reasoning", delta: reasoning });
|
|
86
|
+
}
|
|
87
|
+
if (text) {
|
|
88
|
+
chunks.push({ kind: "text", delta: text });
|
|
89
|
+
}
|
|
90
|
+
return chunks;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Adapt the raw LangGraph `["messages" | "updates", ...]` stream into a typed
|
|
94
|
+
* `AgentStreamChunk` stream for the application layer.
|
|
95
|
+
*/
|
|
96
|
+
export function adaptRawStream(raw) {
|
|
97
|
+
return __asyncGenerator(this, arguments, function* adaptRawStream_1() {
|
|
98
|
+
var _a, e_1, _b, _c;
|
|
99
|
+
try {
|
|
100
|
+
for (var _d = true, raw_1 = __asyncValues(raw), raw_1_1; raw_1_1 = yield __await(raw_1.next()), _a = raw_1_1.done, !_a; _d = true) {
|
|
101
|
+
_c = raw_1_1.value;
|
|
102
|
+
_d = false;
|
|
103
|
+
const entry = _c;
|
|
104
|
+
for (const chunk of parseRawStreamChunk(entry)) {
|
|
105
|
+
yield yield __await(chunk);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
110
|
+
finally {
|
|
111
|
+
try {
|
|
112
|
+
if (!_d && !_a && (_b = raw_1.return)) yield __await(_b.call(raw_1));
|
|
113
|
+
}
|
|
114
|
+
finally { if (e_1) throw e_1.error; }
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
import type { AdminUser, IAdminForth } from "adminforth";
|
|
2
2
|
import type { ChatSurfaceIncomingMessage } from "adminforth";
|
|
3
|
-
import type { PreviousUserMessage } from "
|
|
4
|
-
import type { PluginOptions } from "
|
|
3
|
+
import type { PreviousUserMessage } from "../domain/languageDetect.js";
|
|
4
|
+
import type { PluginOptions } from "../types.js";
|
|
5
5
|
export declare const AGENT_SYSTEM_TURN_PROMPT = "__adminforth_system_message__";
|
|
6
|
+
export declare const STEER_PROMPT_MARKER = "__adminforth_steer__:";
|
|
6
7
|
export declare class AgentSessionStore {
|
|
7
8
|
private getAdminforth;
|
|
8
9
|
private options;
|
|
9
10
|
constructor(getAdminforth: () => IAdminForth, options: PluginOptions);
|
|
10
11
|
createNewTurn(sessionId: string, prompt: string, response?: string): Promise<any>;
|
|
11
12
|
createSystemTurn(sessionId: string, systemMessage: string): Promise<any>;
|
|
13
|
+
/**
|
|
14
|
+
* Append a mid-turn steer to the current (running) turn's prompt instead of creating a
|
|
15
|
+
* new record. Targets the latest non-system turn so a steer attaches to the real
|
|
16
|
+
* conversation turn, never an audio/system note.
|
|
17
|
+
*/
|
|
18
|
+
appendSteerToCurrentTurn(sessionId: string, steerText: string): Promise<void>;
|
|
12
19
|
getSessionTurns(sessionId: string): Promise<{
|
|
13
20
|
prompt: any;
|
|
14
21
|
response: any;
|
|
@@ -17,4 +24,14 @@ export declare class AgentSessionStore {
|
|
|
17
24
|
getLatestTurn(sessionId: string): Promise<any>;
|
|
18
25
|
getChatSurfaceSessionId(incoming: ChatSurfaceIncomingMessage): string;
|
|
19
26
|
getOrCreateChatSurfaceSession(incoming: ChatSurfaceIncomingMessage, adminUser: AdminUser): Promise<string>;
|
|
27
|
+
touchSession(sessionId: string): Promise<void>;
|
|
28
|
+
saveTurnResponse(input: {
|
|
29
|
+
turnId: string;
|
|
30
|
+
responseText: string;
|
|
31
|
+
debugHistory?: unknown;
|
|
32
|
+
}): Promise<void>;
|
|
33
|
+
getResumeState(sessionId: string): Promise<{
|
|
34
|
+
turnId: string;
|
|
35
|
+
initialResponse: string;
|
|
36
|
+
}>;
|
|
20
37
|
}
|
|
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
import { Filters, Sorts } from "adminforth";
|
|
11
11
|
import { randomUUID } from "crypto";
|
|
12
12
|
export const AGENT_SYSTEM_TURN_PROMPT = "__adminforth_system_message__";
|
|
13
|
+
export const STEER_PROMPT_MARKER = "__adminforth_steer__:";
|
|
13
14
|
export class AgentSessionStore {
|
|
14
15
|
constructor(getAdminforth, options) {
|
|
15
16
|
this.getAdminforth = getAdminforth;
|
|
@@ -41,6 +42,25 @@ export class AgentSessionStore {
|
|
|
41
42
|
return newTurn.createdRecord[this.options.turnResource.idField];
|
|
42
43
|
});
|
|
43
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Append a mid-turn steer to the current (running) turn's prompt instead of creating a
|
|
47
|
+
* new record. Targets the latest non-system turn so a steer attaches to the real
|
|
48
|
+
* conversation turn, never an audio/system note.
|
|
49
|
+
*/
|
|
50
|
+
appendSteerToCurrentTurn(sessionId, steerText) {
|
|
51
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
52
|
+
var _a;
|
|
53
|
+
const turns = yield this.getAdminforth().resource(this.options.turnResource.resourceId).list([Filters.EQ(this.options.turnResource.sessionIdField, sessionId)], undefined, undefined, [Sorts.DESC(this.options.turnResource.createdAtField)]);
|
|
54
|
+
const turn = turns.find((candidate) => candidate[this.options.turnResource.promptField] !== AGENT_SYSTEM_TURN_PROMPT);
|
|
55
|
+
if (!turn) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const currentPrompt = (_a = turn[this.options.turnResource.promptField]) !== null && _a !== void 0 ? _a : "";
|
|
59
|
+
yield this.getAdminforth().resource(this.options.turnResource.resourceId).update(turn[this.options.turnResource.idField], {
|
|
60
|
+
[this.options.turnResource.promptField]: `${currentPrompt}${STEER_PROMPT_MARKER}${steerText}`,
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
|
44
64
|
getSessionTurns(sessionId) {
|
|
45
65
|
return __awaiter(this, void 0, void 0, function* () {
|
|
46
66
|
const turns = yield this.getAdminforth().resource(this.options.turnResource.resourceId).list([Filters.EQ(this.options.turnResource.sessionIdField, sessionId)], undefined, undefined, [Sorts.ASC(this.options.turnResource.createdAtField)]);
|
|
@@ -86,4 +106,37 @@ export class AgentSessionStore {
|
|
|
86
106
|
return sessionId;
|
|
87
107
|
});
|
|
88
108
|
}
|
|
109
|
+
touchSession(sessionId) {
|
|
110
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
111
|
+
yield this.getAdminforth().resource(this.options.sessionResource.resourceId).update(sessionId, {
|
|
112
|
+
[this.options.sessionResource.createdAtField]: new Date().toISOString(),
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
saveTurnResponse(input) {
|
|
117
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
118
|
+
const turnUpdates = {
|
|
119
|
+
[this.options.turnResource.responseField]: input.responseText,
|
|
120
|
+
};
|
|
121
|
+
if (this.options.turnResource.debugField) {
|
|
122
|
+
turnUpdates[this.options.turnResource.debugField] = input.debugHistory;
|
|
123
|
+
}
|
|
124
|
+
yield this.getAdminforth()
|
|
125
|
+
.resource(this.options.turnResource.resourceId)
|
|
126
|
+
.update(input.turnId, turnUpdates);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
getResumeState(sessionId) {
|
|
130
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
131
|
+
const latestTurn = yield this.getLatestTurn(sessionId);
|
|
132
|
+
if (!latestTurn) {
|
|
133
|
+
throw new Error(`No agent turn found for session "${sessionId}".`);
|
|
134
|
+
}
|
|
135
|
+
const response = latestTurn[this.options.turnResource.responseField];
|
|
136
|
+
return {
|
|
137
|
+
turnId: latestTurn[this.options.turnResource.idField],
|
|
138
|
+
initialResponse: response === "not_finished" ? "" : String(response),
|
|
139
|
+
};
|
|
140
|
+
});
|
|
141
|
+
}
|
|
89
142
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { IAdminForth } from "adminforth";
|
|
2
|
-
import type { ApiBasedTool } from "
|
|
2
|
+
import type { ApiBasedTool } from "./apiBasedTools.js";
|
|
3
3
|
export declare class AgentToolProvider {
|
|
4
4
|
private readonly getAdminforth;
|
|
5
5
|
private readonly getInternalAgentResourceIds;
|
|
@@ -7,7 +7,7 @@ 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 { prepareApiBasedTools } from "
|
|
10
|
+
import { prepareApiBasedTools } from "./apiBasedTools.js";
|
|
11
11
|
import { createAgentTools } from "./index.js";
|
|
12
12
|
export class AgentToolProvider {
|
|
13
13
|
constructor(getAdminforth, getInternalAgentResourceIds) {
|
|
@@ -385,7 +385,6 @@ function callOpenApiSchema(params) {
|
|
|
385
385
|
return validationErrorResponse('REQUEST_VALIDATION_FAILED', requestValidation.errors);
|
|
386
386
|
}
|
|
387
387
|
const response = createDirectToolResponse();
|
|
388
|
-
logger.info(`Calling OpenAPI tool "${toolName}" with direct handler`);
|
|
389
388
|
const lang = acceptLanguage !== null && acceptLanguage !== void 0 ? acceptLanguage : "en";
|
|
390
389
|
const tr = (msg, category, trParams, pluralizationNumber) => adminforth.tr(msg, category, lang, trParams, pluralizationNumber);
|
|
391
390
|
const output = yield withToolHandlerTimeout((handlerAbortSignal) => schema.handler({
|
|
@@ -449,8 +448,6 @@ export function prepareApiBasedTools(adminforth, hiddenResourceIds = []) {
|
|
|
449
448
|
openApiSchemasByToolName.set(toolName, schema);
|
|
450
449
|
}
|
|
451
450
|
}
|
|
452
|
-
logger.info(`AdminForth Agent OpenAPI APIs: ${formatLogNameList(adminforth.openApi.registeredSchemas.map((schema) => openApiSchemaPathToToolName(schema.path, adminforth)))}`);
|
|
453
|
-
logger.info(`AdminForth Agent OpenAPI tools connected: ${formatLogNameList([...openApiSchemasByToolName.keys()])}`);
|
|
454
451
|
for (const [toolName, schema] of openApiSchemasByToolName.entries()) {
|
|
455
452
|
apiBasedTools[toolName] = {
|
|
456
453
|
description: schema.description,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ApiBasedTool } from "
|
|
1
|
+
import type { ApiBasedTool } from "./apiBasedTools.js";
|
|
2
2
|
export declare function createApiTool(toolName: string, apiBasedTool: ApiBasedTool): import("langchain").DynamicStructuredTool<Record<string, unknown> | {
|
|
3
3
|
readonly type: "object";
|
|
4
4
|
readonly properties: {};
|
|
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
};
|
|
10
10
|
import { tool } from "langchain";
|
|
11
11
|
import { z } from "zod";
|
|
12
|
-
import { listSkillManifests, loadSkillMarkdown, } from "
|
|
12
|
+
import { listSkillManifests, loadSkillMarkdown, } from "./skills/registry.js";
|
|
13
13
|
const fetchSkillSchema = z.object({
|
|
14
14
|
skillName: z
|
|
15
15
|
.string()
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import type { ApiBasedTool } from "
|
|
2
|
+
import type { ApiBasedTool } from "./apiBasedTools.js";
|
|
3
3
|
export declare function createFetchToolSchemaTool(apiBasedTools: Record<string, ApiBasedTool>): Promise<import("langchain").DynamicStructuredTool<z.ZodObject<{
|
|
4
4
|
toolName: z.ZodString;
|
|
5
5
|
}, z.core.$strip>, {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { ClientTool } from "@langchain/core/tools";
|
|
2
|
-
import type { ApiBasedTool } from "
|
|
2
|
+
import type { ApiBasedTool } from "./apiBasedTools.js";
|
|
3
3
|
export declare const ALWAYS_AVAILABLE_API_TOOL_NAMES: readonly ["get_resource"];
|
|
4
4
|
export declare function createAgentTools(customComponentsDir: string, apiBasedTools: Record<string, ApiBasedTool>, pluginCustomFolderPaths?: string[]): Promise<ClientTool[]>;
|
|
@@ -17,8 +17,8 @@ export declare function createNavigateUserTool(): import("langchain").DynamicStr
|
|
|
17
17
|
sort: z.ZodOptional<z.ZodObject<{
|
|
18
18
|
column: z.ZodString;
|
|
19
19
|
direction: z.ZodEnum<{
|
|
20
|
-
asc: "asc";
|
|
21
20
|
desc: "desc";
|
|
21
|
+
asc: "asc";
|
|
22
22
|
}>;
|
|
23
23
|
}, z.core.$strip>>;
|
|
24
24
|
query: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
@@ -34,7 +34,7 @@ export declare function createNavigateUserTool(): import("langchain").DynamicStr
|
|
|
34
34
|
}[] | undefined;
|
|
35
35
|
sort?: {
|
|
36
36
|
column: string;
|
|
37
|
-
direction: "
|
|
37
|
+
direction: "desc" | "asc";
|
|
38
38
|
} | undefined;
|
|
39
39
|
query?: Record<string, string | number | boolean> | undefined;
|
|
40
40
|
}, {
|
|
@@ -49,7 +49,7 @@ export declare function createNavigateUserTool(): import("langchain").DynamicStr
|
|
|
49
49
|
}[] | undefined;
|
|
50
50
|
sort?: {
|
|
51
51
|
column: string;
|
|
52
|
-
direction: "
|
|
52
|
+
direction: "desc" | "asc";
|
|
53
53
|
} | undefined;
|
|
54
54
|
query?: Record<string, string | number | boolean> | undefined;
|
|
55
55
|
}, string, unknown, "navigate_user">;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ChatSurfaceAdapter, ChatSurfaceEventSink, ChatSurfaceIncomingMessage, IAdminForth } from "adminforth";
|
|
2
|
-
import type { HandleSpeechTurnInput, HandleTurnInput, RunAndPersistAgentResponseInput, RunAndPersistAgentResponseResult } from "
|
|
3
|
-
import type { PluginOptions } from "
|
|
2
|
+
import type { HandleSpeechTurnInput, HandleTurnInput, RunAndPersistAgentResponseInput, RunAndPersistAgentResponseResult } from "../../domain/turnTypes.js";
|
|
3
|
+
import type { PluginOptions } from "../../types.js";
|
|
4
4
|
export type SessionTurn = {
|
|
5
5
|
prompt: string;
|
|
6
6
|
response: string;
|
|
@@ -10,12 +10,20 @@ export type AgentEndpointsContext = {
|
|
|
10
10
|
options: PluginOptions;
|
|
11
11
|
handleTurn(input: HandleTurnInput): Promise<RunAndPersistAgentResponseResult>;
|
|
12
12
|
handleSpeechTurn(input: HandleSpeechTurnInput): Promise<RunAndPersistAgentResponseResult | null>;
|
|
13
|
+
steer(input: {
|
|
14
|
+
sessionId: string;
|
|
15
|
+
message: string;
|
|
16
|
+
}): {
|
|
17
|
+
id: string;
|
|
18
|
+
queued: number;
|
|
19
|
+
};
|
|
13
20
|
runAndPersistAgentResponse(input: RunAndPersistAgentResponseInput): Promise<RunAndPersistAgentResponseResult>;
|
|
14
21
|
getSessionTurns(sessionId: string): Promise<SessionTurn[]>;
|
|
15
22
|
createNewTurn(sessionId: string, prompt: string, response?: string): Promise<string>;
|
|
16
23
|
createSystemTurn(sessionId: string, systemMessage: string): Promise<string>;
|
|
24
|
+
appendSteerToCurrentTurn(sessionId: string, steerText: string): Promise<void>;
|
|
17
25
|
handleChatSurfaceMessage(adapter: ChatSurfaceAdapter, incoming: ChatSurfaceIncomingMessage, sink: ChatSurfaceEventSink): Promise<void>;
|
|
18
26
|
};
|
|
19
|
-
export type CoreEndpointsContext = Pick<AgentEndpointsContext, "options" | "handleTurn" | "handleSpeechTurn">;
|
|
20
|
-
export type SessionEndpointsContext = Pick<AgentEndpointsContext, "adminforth" | "options" | "getSessionTurns" | "createNewTurn" | "createSystemTurn">;
|
|
27
|
+
export type CoreEndpointsContext = Pick<AgentEndpointsContext, "options" | "handleTurn" | "handleSpeechTurn" | "steer">;
|
|
28
|
+
export type SessionEndpointsContext = Pick<AgentEndpointsContext, "adminforth" | "options" | "getSessionTurns" | "createNewTurn" | "createSystemTurn" | "appendSteerToCurrentTurn">;
|
|
21
29
|
export type ChatSurfaceEndpointsContext = Pick<AgentEndpointsContext, "adminforth" | "options" | "handleChatSurfaceMessage">;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -8,7 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { z } from "zod";
|
|
11
|
-
import { createSseEventEmitter } from "../
|
|
11
|
+
import { createSseEventEmitter } from "../sse/sseWriter.js";
|
|
12
12
|
const currentPageContextSchema = z.object({
|
|
13
13
|
path: z.string(),
|
|
14
14
|
fullPath: z.string(),
|
|
@@ -26,6 +26,10 @@ const agentApprovalBodySchema = z.object({
|
|
|
26
26
|
sessionId: z.string(),
|
|
27
27
|
decision: z.enum(["approve", "reject"]),
|
|
28
28
|
}).strict();
|
|
29
|
+
const agentSteerBodySchema = z.object({
|
|
30
|
+
sessionId: z.string(),
|
|
31
|
+
message: z.string().min(1),
|
|
32
|
+
}).strict();
|
|
29
33
|
// Sent as multipart/form-data (via multer), so every field arrives as a plain string on the wire.
|
|
30
34
|
// `currentPage` is JSON.stringify'd by the client into a form field and must be parsed back into
|
|
31
35
|
// an object. Zod -> JSON-Schema conversion cannot represent `.transform()` at all (it throws), so
|
|
@@ -77,7 +81,7 @@ export function setupCoreEndpoints(ctx, server) {
|
|
|
77
81
|
method: 'POST',
|
|
78
82
|
path: `/agent/response`,
|
|
79
83
|
request_schema: agentResponseBodySchema,
|
|
80
|
-
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser,
|
|
84
|
+
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, _raw_express_res, abortSignal }) {
|
|
81
85
|
var _b;
|
|
82
86
|
const data = body;
|
|
83
87
|
const emit = createSseEventEmitter(_raw_express_res, {
|
|
@@ -103,7 +107,7 @@ export function setupCoreEndpoints(ctx, server) {
|
|
|
103
107
|
method: 'POST',
|
|
104
108
|
path: `/agent/approval`,
|
|
105
109
|
request_schema: agentApprovalBodySchema,
|
|
106
|
-
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser,
|
|
110
|
+
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, _raw_express_res, abortSignal }) {
|
|
107
111
|
const data = body;
|
|
108
112
|
const emit = createSseEventEmitter(_raw_express_res, {
|
|
109
113
|
vercelAiUiMessageStream: true,
|
|
@@ -122,6 +126,22 @@ export function setupCoreEndpoints(ctx, server) {
|
|
|
122
126
|
return null;
|
|
123
127
|
})
|
|
124
128
|
});
|
|
129
|
+
server.endpoint({
|
|
130
|
+
method: 'POST',
|
|
131
|
+
path: `/agent/steer`,
|
|
132
|
+
request_schema: agentSteerBodySchema,
|
|
133
|
+
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body }) {
|
|
134
|
+
const data = body;
|
|
135
|
+
// Fire-and-forget: the steer is buffered and folded into the running turn by the
|
|
136
|
+
// beforeModel steer middleware, which signals `data-steer-applied` on that turn's
|
|
137
|
+
// SSE stream once consumed. This endpoint only confirms it was received/queued.
|
|
138
|
+
const { id, queued } = ctx.steer({
|
|
139
|
+
sessionId: data.sessionId,
|
|
140
|
+
message: data.message,
|
|
141
|
+
});
|
|
142
|
+
return { ok: true, id, queued };
|
|
143
|
+
})
|
|
144
|
+
});
|
|
125
145
|
server.endpoint({
|
|
126
146
|
method: 'POST',
|
|
127
147
|
path: `/agent/speech-response`,
|
|
@@ -10,11 +10,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
import { Filters, Sorts } from "adminforth";
|
|
11
11
|
import { randomUUID } from "crypto";
|
|
12
12
|
import { z } from "zod";
|
|
13
|
-
import { AGENT_SYSTEM_TURN_PROMPT } from "
|
|
13
|
+
import { AGENT_SYSTEM_TURN_PROMPT } from "../../persistence/sessionStore.js";
|
|
14
14
|
const addSystemMessageBodySchema = z.object({
|
|
15
15
|
sessionId: z.string(),
|
|
16
16
|
systemMessage: z.string(),
|
|
17
17
|
}).strict();
|
|
18
|
+
const appendSteerBodySchema = z.object({
|
|
19
|
+
sessionId: z.string(),
|
|
20
|
+
message: z.string().min(1),
|
|
21
|
+
}).strict();
|
|
18
22
|
const getSessionsBodySchema = z.object({
|
|
19
23
|
limit: z.number().int().min(1).max(100).optional(),
|
|
20
24
|
}).strict();
|
|
@@ -54,11 +58,13 @@ export function setupSessionEndpoints(ctx, server) {
|
|
|
54
58
|
const sessionId = data.sessionId;
|
|
55
59
|
const session = yield ctx.adminforth.resource(ctx.options.sessionResource.resourceId).get([Filters.EQ(ctx.options.sessionResource.idField, sessionId)]);
|
|
56
60
|
if (!session) {
|
|
61
|
+
response.setStatus(404, 'Session not found');
|
|
57
62
|
return {
|
|
58
63
|
error: 'Session not found'
|
|
59
64
|
};
|
|
60
65
|
}
|
|
61
66
|
if (session[ctx.options.sessionResource.askerIdField] !== userId) {
|
|
67
|
+
response.setStatus(403, 'Unauthorized');
|
|
62
68
|
return {
|
|
63
69
|
error: 'Unauthorized'
|
|
64
70
|
};
|
|
@@ -129,11 +135,13 @@ export function setupSessionEndpoints(ctx, server) {
|
|
|
129
135
|
const userId = adminUser.pk;
|
|
130
136
|
const session = yield ctx.adminforth.resource(ctx.options.sessionResource.resourceId).get([Filters.EQ(ctx.options.sessionResource.idField, sessionId)]);
|
|
131
137
|
if (!session) {
|
|
138
|
+
response.setStatus(404, 'Session not found');
|
|
132
139
|
return {
|
|
133
140
|
error: 'Session not found'
|
|
134
141
|
};
|
|
135
142
|
}
|
|
136
143
|
if (session[ctx.options.sessionResource.askerIdField] !== userId) {
|
|
144
|
+
response.setStatus(403, 'Unauthorized');
|
|
137
145
|
return {
|
|
138
146
|
error: 'Unauthorized'
|
|
139
147
|
};
|
|
@@ -154,11 +162,13 @@ export function setupSessionEndpoints(ctx, server) {
|
|
|
154
162
|
const data = body;
|
|
155
163
|
const session = yield ctx.adminforth.resource(ctx.options.sessionResource.resourceId).get([Filters.EQ(ctx.options.sessionResource.idField, data.sessionId)]);
|
|
156
164
|
if (!session) {
|
|
165
|
+
response.setStatus(404, 'Session not found');
|
|
157
166
|
return {
|
|
158
167
|
error: 'Session not found'
|
|
159
168
|
};
|
|
160
169
|
}
|
|
161
170
|
if (session[ctx.options.sessionResource.askerIdField] !== adminUser.pk) {
|
|
171
|
+
response.setStatus(403, 'Unauthorized');
|
|
162
172
|
return {
|
|
163
173
|
error: 'Unauthorized'
|
|
164
174
|
};
|
|
@@ -169,4 +179,29 @@ export function setupSessionEndpoints(ctx, server) {
|
|
|
169
179
|
};
|
|
170
180
|
})
|
|
171
181
|
});
|
|
182
|
+
server.endpoint({
|
|
183
|
+
method: 'POST',
|
|
184
|
+
path: `/agent/append-steer-to-turn`,
|
|
185
|
+
request_schema: appendSteerBodySchema,
|
|
186
|
+
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response }) {
|
|
187
|
+
const data = body;
|
|
188
|
+
const session = yield ctx.adminforth.resource(ctx.options.sessionResource.resourceId).get([Filters.EQ(ctx.options.sessionResource.idField, data.sessionId)]);
|
|
189
|
+
if (!session) {
|
|
190
|
+
response.setStatus(404, 'Session not found');
|
|
191
|
+
return {
|
|
192
|
+
error: 'Session not found'
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
if (session[ctx.options.sessionResource.askerIdField] !== adminUser.pk) {
|
|
196
|
+
response.setStatus(403, 'Unauthorized');
|
|
197
|
+
return {
|
|
198
|
+
error: 'Unauthorized'
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
yield ctx.appendSteerToCurrentTurn(data.sessionId, data.message);
|
|
202
|
+
return {
|
|
203
|
+
ok: true
|
|
204
|
+
};
|
|
205
|
+
})
|
|
206
|
+
});
|
|
172
207
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { AgentEventEmitter } from "../../domain/agentEvents.js";
|
|
2
|
+
type AgentEventStreamResponse = {
|
|
3
|
+
writeHead: (statusCode: number, headers: Record<string, string>) => void;
|
|
4
|
+
write: (chunk: string) => unknown;
|
|
5
|
+
end: () => unknown;
|
|
6
|
+
writableEnded: boolean;
|
|
7
|
+
destroyed: boolean;
|
|
8
|
+
};
|
|
9
|
+
type AgentEventStreamOptions = {
|
|
10
|
+
vercelAiUiMessageStream?: boolean;
|
|
11
|
+
closeActiveBlockOnToolStart?: boolean;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Maps the internal {@link AgentEvent} vocabulary onto the two Server-Sent-Events
|
|
15
|
+
* wire dialects the frontend consumes. Both dialects are HARD external contracts —
|
|
16
|
+
* do not change frame names/shapes without updating the corresponding consumer:
|
|
17
|
+
*
|
|
18
|
+
* - `vercelAiUiMessageStream: true` (used by `/agent/response` and `/agent/approval`):
|
|
19
|
+
* the Vercel AI SDK message-stream v1 format (`start`, `text-start`/`text-delta`/
|
|
20
|
+
* `text-end`, `reasoning-*`, `data-*` parts including `data-steer-applied`,
|
|
21
|
+
* `error` with `errorText`, `finish`, `[DONE]`). Consumed by `DefaultChatTransport`
|
|
22
|
+
* and the manual approval parser in `custom/composables/agentStore/useAgentChat.ts`.
|
|
23
|
+
* - default (used by `/agent/speech-response`): bare event names
|
|
24
|
+
* (`transcript`, `speech-response`, `audio-start`/`audio-delta`/`audio-done`,
|
|
25
|
+
* `open-page`, `error`) plus the Vercel-shaped `data-tool-call`. Consumed by
|
|
26
|
+
* `custom/composables/useAgentAudio.ts`.
|
|
27
|
+
*/
|
|
28
|
+
export declare function createSseEventEmitter(res: AgentEventStreamResponse, options?: AgentEventStreamOptions): AgentEventEmitter;
|
|
29
|
+
export {};
|
|
@@ -98,6 +98,15 @@ function createAgentEventStream(res, options = {}) {
|
|
|
98
98
|
},
|
|
99
99
|
});
|
|
100
100
|
},
|
|
101
|
+
steerApplied(count, ids) {
|
|
102
|
+
stream.send({
|
|
103
|
+
type: isAiUiMessageStream ? "data-steer-applied" : "steer-applied",
|
|
104
|
+
data: {
|
|
105
|
+
count,
|
|
106
|
+
ids,
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
},
|
|
101
110
|
openPage(targetPath) {
|
|
102
111
|
stream.send({
|
|
103
112
|
type: isAiUiMessageStream ? "data-open-page" : "open-page",
|
|
@@ -185,6 +194,21 @@ function createAgentEventStream(res, options = {}) {
|
|
|
185
194
|
};
|
|
186
195
|
return stream;
|
|
187
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* Maps the internal {@link AgentEvent} vocabulary onto the two Server-Sent-Events
|
|
199
|
+
* wire dialects the frontend consumes. Both dialects are HARD external contracts —
|
|
200
|
+
* do not change frame names/shapes without updating the corresponding consumer:
|
|
201
|
+
*
|
|
202
|
+
* - `vercelAiUiMessageStream: true` (used by `/agent/response` and `/agent/approval`):
|
|
203
|
+
* the Vercel AI SDK message-stream v1 format (`start`, `text-start`/`text-delta`/
|
|
204
|
+
* `text-end`, `reasoning-*`, `data-*` parts including `data-steer-applied`,
|
|
205
|
+
* `error` with `errorText`, `finish`, `[DONE]`). Consumed by `DefaultChatTransport`
|
|
206
|
+
* and the manual approval parser in `custom/composables/agentStore/useAgentChat.ts`.
|
|
207
|
+
* - default (used by `/agent/speech-response`): bare event names
|
|
208
|
+
* (`transcript`, `speech-response`, `audio-start`/`audio-delta`/`audio-done`,
|
|
209
|
+
* `open-page`, `error`) plus the Vercel-shaped `data-tool-call`. Consumed by
|
|
210
|
+
* `custom/composables/useAgentAudio.ts`.
|
|
211
|
+
*/
|
|
188
212
|
export function createSseEventEmitter(res, options = {}) {
|
|
189
213
|
const stream = createAgentEventStream(res, options);
|
|
190
214
|
return (event) => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -207,6 +231,9 @@ export function createSseEventEmitter(res, options = {}) {
|
|
|
207
231
|
case "interrupt":
|
|
208
232
|
stream.interrupt(event.sessionId, event.interrupt);
|
|
209
233
|
break;
|
|
234
|
+
case "steer-applied":
|
|
235
|
+
stream.steerApplied(event.count, event.ids);
|
|
236
|
+
break;
|
|
210
237
|
case "open-page":
|
|
211
238
|
stream.openPage(event.targetPath);
|
|
212
239
|
break;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ChatSurfaceAdapter, ChatSurfaceEventSink, ChatSurfaceIncomingMessage, IAdminForth } from "adminforth";
|
|
2
|
-
import type { HandleTurnInput, RunAndPersistAgentResponseInput, RunAndPersistAgentResponseResult } from "
|
|
3
|
-
import type { AgentSessionStore } from "
|
|
4
|
-
import type { PluginOptions } from "
|
|
2
|
+
import type { HandleTurnInput, RunAndPersistAgentResponseInput, RunAndPersistAgentResponseResult } from "../../domain/turnTypes.js";
|
|
3
|
+
import type { AgentSessionStore } from "../../persistence/sessionStore.js";
|
|
4
|
+
import type { PluginOptions } from "../../types.js";
|
|
5
5
|
export declare class ChatSurfaceService {
|
|
6
6
|
private getAdminforth;
|
|
7
7
|
private options;
|
|
@@ -8,8 +8,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { Filters, logger } from "adminforth";
|
|
11
|
-
import { getErrorMessage, isAbortError } from "
|
|
12
|
-
import { sanitizeSpeechText } from "
|
|
11
|
+
import { getErrorMessage, isAbortError } from "../../shared/errors.js";
|
|
12
|
+
import { sanitizeSpeechText } from "../../shared/sanitizeSpeechText.js";
|
|
13
13
|
export class ChatSurfaceService {
|
|
14
14
|
constructor(getAdminforth, options, sessionStore, handleTurn, runAndPersistAgentResponse) {
|
|
15
15
|
this.getAdminforth = getAdminforth;
|
|
@@ -35,9 +35,11 @@ export class ChatSurfaceService {
|
|
|
35
35
|
return;
|
|
36
36
|
}
|
|
37
37
|
if (event.type === "error") {
|
|
38
|
+
// Full error detail is logged server-side (see runAndPersistAgentResponse);
|
|
39
|
+
// external chat users receive a generic message to avoid leaking internals.
|
|
38
40
|
yield sink.emit({
|
|
39
41
|
type: "error",
|
|
40
|
-
message:
|
|
42
|
+
message: "Agent response failed. Check server logs for details.",
|
|
41
43
|
});
|
|
42
44
|
}
|
|
43
45
|
});
|
|
@@ -122,7 +124,7 @@ export class ChatSurfaceService {
|
|
|
122
124
|
logger.error(`Agent ${incoming.surface} surface speech synthesis failed:\n${getErrorMessage(error)}`);
|
|
123
125
|
yield sink.emit({
|
|
124
126
|
type: "error",
|
|
125
|
-
message:
|
|
127
|
+
message: "Speech synthesis failed. Check server logs for details.",
|
|
126
128
|
});
|
|
127
129
|
}
|
|
128
130
|
});
|
|
@@ -165,7 +167,7 @@ export class ChatSurfaceService {
|
|
|
165
167
|
if (agentResponse.failed) {
|
|
166
168
|
yield sink.emit({
|
|
167
169
|
type: "error",
|
|
168
|
-
message:
|
|
170
|
+
message: "Agent response failed. Check server logs for details.",
|
|
169
171
|
});
|
|
170
172
|
}
|
|
171
173
|
return agentResponse;
|
package/dist/{agent/speech/SpeechTurnService.d.ts → transport/surfaces/speechTurnService.d.ts}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { RunAndPersistAgentResponseInput, RunAndPersistAgentResponseResult, SpeechAgentTurnInput } from "
|
|
1
|
+
import type { RunAndPersistAgentResponseInput, RunAndPersistAgentResponseResult, SpeechAgentTurnInput } from "../../domain/turnTypes.js";
|
|
2
2
|
export declare class SpeechTurnService {
|
|
3
3
|
private readonly runAndPersistAgentResponse;
|
|
4
4
|
constructor(runAndPersistAgentResponse: (input: RunAndPersistAgentResponseInput) => Promise<RunAndPersistAgentResponseResult>);
|