@wingman-ai/gateway 0.2.2 → 0.2.3
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/.wingman/agents/coding/agent.md +174 -169
- package/.wingman/agents/coding/implementor.md +25 -1
- package/.wingman/agents/main/agent.md +4 -0
- package/README.md +1 -0
- package/dist/agent/config/agentConfig.cjs +1 -1
- package/dist/agent/config/agentConfig.js +1 -1
- package/dist/agent/config/modelFactory.cjs +22 -2
- package/dist/agent/config/modelFactory.d.ts +2 -0
- package/dist/agent/config/modelFactory.js +22 -2
- package/dist/agent/tests/modelFactory.test.cjs +12 -5
- package/dist/agent/tests/modelFactory.test.js +12 -5
- package/dist/cli/commands/init.cjs +7 -6
- package/dist/cli/commands/init.js +7 -6
- package/dist/cli/commands/provider.cjs +17 -3
- package/dist/cli/commands/provider.js +17 -3
- package/dist/cli/config/loader.cjs +27 -0
- package/dist/cli/config/loader.js +27 -0
- package/dist/cli/config/schema.cjs +80 -2
- package/dist/cli/config/schema.d.ts +88 -0
- package/dist/cli/config/schema.js +67 -1
- package/dist/cli/core/agentInvoker.cjs +191 -13
- package/dist/cli/core/agentInvoker.d.ts +42 -3
- package/dist/cli/core/agentInvoker.js +163 -9
- package/dist/cli/core/sessionManager.cjs +32 -5
- package/dist/cli/core/sessionManager.js +32 -5
- package/dist/cli/index.cjs +6 -5
- package/dist/cli/index.js +6 -5
- package/dist/cli/types.d.ts +32 -0
- package/dist/gateway/http/sessions.cjs +7 -7
- package/dist/gateway/http/sessions.js +7 -7
- package/dist/gateway/server.cjs +191 -41
- package/dist/gateway/server.d.ts +8 -1
- package/dist/gateway/server.js +191 -41
- package/dist/gateway/types.d.ts +1 -0
- package/dist/providers/codex.cjs +167 -0
- package/dist/providers/codex.d.ts +15 -0
- package/dist/providers/codex.js +127 -0
- package/dist/providers/credentials.cjs +8 -0
- package/dist/providers/credentials.js +8 -0
- package/dist/providers/registry.cjs +11 -0
- package/dist/providers/registry.d.ts +1 -1
- package/dist/providers/registry.js +11 -0
- package/dist/tests/agentInvokerSummarization.test.cjs +296 -0
- package/dist/tests/agentInvokerSummarization.test.d.ts +1 -0
- package/dist/tests/agentInvokerSummarization.test.js +290 -0
- package/dist/tests/cli-config-loader.test.cjs +88 -0
- package/dist/tests/cli-config-loader.test.js +88 -0
- package/dist/tests/codex-credentials-precedence.test.cjs +94 -0
- package/dist/tests/codex-credentials-precedence.test.d.ts +1 -0
- package/dist/tests/codex-credentials-precedence.test.js +88 -0
- package/dist/tests/codex-provider.test.cjs +186 -0
- package/dist/tests/codex-provider.test.d.ts +1 -0
- package/dist/tests/codex-provider.test.js +180 -0
- package/dist/tests/gateway.test.cjs +108 -1
- package/dist/tests/gateway.test.js +108 -1
- package/dist/tests/provider-command-codex.test.cjs +57 -0
- package/dist/tests/provider-command-codex.test.d.ts +1 -0
- package/dist/tests/provider-command-codex.test.js +51 -0
- package/dist/tests/sessionStateMessages.test.cjs +38 -0
- package/dist/tests/sessionStateMessages.test.js +38 -0
- package/dist/webui/assets/{index-DDsMIOTX.css → index-BVMavpud.css} +1 -1
- package/dist/webui/assets/index-DCB2aVVf.js +182 -0
- package/dist/webui/index.html +2 -2
- package/package.json +1 -1
- package/dist/webui/assets/index-CPhfGPHc.js +0 -182
|
@@ -24,26 +24,35 @@ var __webpack_require__ = {};
|
|
|
24
24
|
var __webpack_exports__ = {};
|
|
25
25
|
__webpack_require__.r(__webpack_exports__);
|
|
26
26
|
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
resolveToolRetryMiddlewareSettings: ()=>resolveToolRetryMiddlewareSettings,
|
|
28
|
+
resolveSummarizationMiddlewareSettings: ()=>resolveSummarizationMiddlewareSettings,
|
|
29
29
|
OUTPUT_VIRTUAL_PATH: ()=>OUTPUT_VIRTUAL_PATH,
|
|
30
|
-
|
|
31
|
-
AgentInvoker: ()=>AgentInvoker,
|
|
30
|
+
resolveExecutionWorkspace: ()=>resolveExecutionWorkspace,
|
|
32
31
|
buildUserContent: ()=>buildUserContent,
|
|
33
|
-
|
|
32
|
+
toWorkspaceAliasVirtualPath: ()=>toWorkspaceAliasVirtualPath,
|
|
33
|
+
chunkHasAssistantText: ()=>chunkHasAssistantText,
|
|
34
|
+
resolveModelRetryMiddlewareSettings: ()=>resolveModelRetryMiddlewareSettings,
|
|
35
|
+
AgentInvoker: ()=>AgentInvoker,
|
|
36
|
+
detectToolEventContext: ()=>detectToolEventContext,
|
|
37
|
+
WORKDIR_VIRTUAL_PATH: ()=>WORKDIR_VIRTUAL_PATH,
|
|
38
|
+
configureDeepAgentSummarizationMiddleware: ()=>configureDeepAgentSummarizationMiddleware,
|
|
39
|
+
resolveExternalOutputMount: ()=>resolveExternalOutputMount,
|
|
40
|
+
resolveHumanInTheLoopSettings: ()=>resolveHumanInTheLoopSettings,
|
|
41
|
+
selectStreamingFallbackText: ()=>selectStreamingFallbackText
|
|
34
42
|
});
|
|
35
|
-
const external_deepagents_namespaceObject = require("deepagents");
|
|
36
43
|
const external_node_fs_namespaceObject = require("node:fs");
|
|
37
44
|
const external_node_path_namespaceObject = require("node:path");
|
|
45
|
+
const external_deepagents_namespaceObject = require("deepagents");
|
|
46
|
+
const external_langchain_namespaceObject = require("langchain");
|
|
38
47
|
const external_uuid_namespaceObject = require("uuid");
|
|
39
|
-
const
|
|
40
|
-
const loader_cjs_namespaceObject = require("../config/loader.cjs");
|
|
48
|
+
const mcpClientManager_cjs_namespaceObject = require("../../agent/config/mcpClientManager.cjs");
|
|
41
49
|
const additional_messages_cjs_namespaceObject = require("../../agent/middleware/additional-messages.cjs");
|
|
42
|
-
const hooks_cjs_namespaceObject = require("../../agent/middleware/hooks.cjs");
|
|
43
50
|
const merger_cjs_namespaceObject = require("../../agent/middleware/hooks/merger.cjs");
|
|
51
|
+
const hooks_cjs_namespaceObject = require("../../agent/middleware/hooks.cjs");
|
|
44
52
|
const media_compat_cjs_namespaceObject = require("../../agent/middleware/media-compat.cjs");
|
|
45
|
-
const mcpClientManager_cjs_namespaceObject = require("../../agent/config/mcpClientManager.cjs");
|
|
46
53
|
const uiRegistry_cjs_namespaceObject = require("../../agent/uiRegistry.cjs");
|
|
54
|
+
const agentLoader_cjs_namespaceObject = require("../../agent/config/agentLoader.cjs");
|
|
55
|
+
const loader_cjs_namespaceObject = require("../config/loader.cjs");
|
|
47
56
|
function _define_property(obj, key, value) {
|
|
48
57
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
49
58
|
value: value,
|
|
@@ -56,6 +65,7 @@ function _define_property(obj, key, value) {
|
|
|
56
65
|
}
|
|
57
66
|
const WORKDIR_VIRTUAL_PATH = "/workdir/";
|
|
58
67
|
const OUTPUT_VIRTUAL_PATH = "/output/";
|
|
68
|
+
const DEFAULT_DEEPAGENT_MODEL = "claude-sonnet-4-5-20250929";
|
|
59
69
|
const isPathWithinRoot = (targetPath, rootPath)=>{
|
|
60
70
|
const normalizedTarget = (0, external_node_path_namespaceObject.normalize)(targetPath);
|
|
61
71
|
const normalizedRoot = (0, external_node_path_namespaceObject.normalize)(rootPath);
|
|
@@ -88,6 +98,101 @@ const resolveExternalOutputMount = (workspace, workdir, defaultOutputDir)=>{
|
|
|
88
98
|
absolutePath: null
|
|
89
99
|
};
|
|
90
100
|
};
|
|
101
|
+
const resolveSummarizationMiddlewareSettings = (config)=>{
|
|
102
|
+
if (!config.summarization?.enabled) return null;
|
|
103
|
+
return {
|
|
104
|
+
maxTokensBeforeSummary: config.summarization.maxTokensBeforeSummary,
|
|
105
|
+
messagesToKeep: config.summarization.messagesToKeep
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
const resolveModelRetryMiddlewareSettings = (config)=>{
|
|
109
|
+
if (!config.modelRetry?.enabled) return null;
|
|
110
|
+
return {
|
|
111
|
+
maxRetries: config.modelRetry.maxRetries,
|
|
112
|
+
backoffFactor: config.modelRetry.backoffFactor,
|
|
113
|
+
initialDelayMs: config.modelRetry.initialDelayMs,
|
|
114
|
+
maxDelayMs: config.modelRetry.maxDelayMs,
|
|
115
|
+
jitter: config.modelRetry.jitter,
|
|
116
|
+
onFailure: config.modelRetry.onFailure
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
const resolveToolRetryMiddlewareSettings = (config)=>{
|
|
120
|
+
if (!config.toolRetry?.enabled) return null;
|
|
121
|
+
return {
|
|
122
|
+
maxRetries: config.toolRetry.maxRetries,
|
|
123
|
+
backoffFactor: config.toolRetry.backoffFactor,
|
|
124
|
+
initialDelayMs: config.toolRetry.initialDelayMs,
|
|
125
|
+
maxDelayMs: config.toolRetry.maxDelayMs,
|
|
126
|
+
jitter: config.toolRetry.jitter,
|
|
127
|
+
onFailure: config.toolRetry.onFailure,
|
|
128
|
+
...config.toolRetry.tools && config.toolRetry.tools.length > 0 ? {
|
|
129
|
+
tools: config.toolRetry.tools
|
|
130
|
+
} : {}
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
const resolveHumanInTheLoopSettings = (config)=>{
|
|
134
|
+
if (!config.humanInTheLoop?.enabled) return null;
|
|
135
|
+
const interruptOn = config.humanInTheLoop.interruptOn || {};
|
|
136
|
+
if (0 === Object.keys(interruptOn).length) return null;
|
|
137
|
+
return {
|
|
138
|
+
interruptOn
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
const configureDeepAgentSummarizationMiddleware = (agent, settings, model)=>{
|
|
142
|
+
const middleware = agent?.options?.middleware;
|
|
143
|
+
if (!Array.isArray(middleware)) return;
|
|
144
|
+
const index = middleware.findIndex((entry)=>entry?.name === "SummarizationMiddleware");
|
|
145
|
+
if (index < 0) return;
|
|
146
|
+
if (!settings) return void middleware.splice(index, 1);
|
|
147
|
+
middleware[index] = (0, external_langchain_namespaceObject.summarizationMiddleware)({
|
|
148
|
+
model: model || DEFAULT_DEEPAGENT_MODEL,
|
|
149
|
+
trigger: {
|
|
150
|
+
tokens: settings.maxTokensBeforeSummary
|
|
151
|
+
},
|
|
152
|
+
keep: {
|
|
153
|
+
messages: settings.messagesToKeep
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
};
|
|
157
|
+
const detectToolEventContext = (chunk)=>{
|
|
158
|
+
if (!chunk || "object" != typeof chunk || Array.isArray(chunk)) return null;
|
|
159
|
+
const eventChunk = chunk;
|
|
160
|
+
if ("on_tool_start" !== eventChunk.event && "on_tool_end" !== eventChunk.event) return null;
|
|
161
|
+
const toolName = "string" == typeof eventChunk.name && eventChunk.name.trim() ? eventChunk.name.trim() : "unknown";
|
|
162
|
+
return {
|
|
163
|
+
event: eventChunk.event,
|
|
164
|
+
toolName
|
|
165
|
+
};
|
|
166
|
+
};
|
|
167
|
+
const chunkHasAssistantText = (chunk)=>{
|
|
168
|
+
if (!chunk || "object" != typeof chunk || Array.isArray(chunk)) return false;
|
|
169
|
+
const eventChunk = chunk;
|
|
170
|
+
const eventName = "string" == typeof eventChunk.event ? eventChunk.event : void 0;
|
|
171
|
+
if ("on_chat_model_stream" === eventName) {
|
|
172
|
+
const data = eventChunk.data && "object" == typeof eventChunk.data ? eventChunk.data : null;
|
|
173
|
+
const messageChunk = data?.chunk || data?.message;
|
|
174
|
+
const content = messageChunk?.content;
|
|
175
|
+
if ("string" == typeof content) return content.length > 0;
|
|
176
|
+
if (Array.isArray(content)) return content.some((part)=>part && "object" == typeof part && "text" === part.type && "string" == typeof part.text && part.text.length > 0);
|
|
177
|
+
}
|
|
178
|
+
if ("on_llm_stream" === eventName) {
|
|
179
|
+
const data = eventChunk.data && "object" == typeof eventChunk.data ? eventChunk.data : null;
|
|
180
|
+
const llmChunk = data?.chunk && "object" == typeof data.chunk ? data.chunk : null;
|
|
181
|
+
return "string" == typeof llmChunk?.text && llmChunk.text.length > 0;
|
|
182
|
+
}
|
|
183
|
+
return false;
|
|
184
|
+
};
|
|
185
|
+
const selectStreamingFallbackText = (sessionMessages, invocationStartedAt, windowMs = 1000)=>{
|
|
186
|
+
for(let i = sessionMessages.length - 1; i >= 0; i -= 1){
|
|
187
|
+
const message = sessionMessages[i];
|
|
188
|
+
if (!message || "object" != typeof message) continue;
|
|
189
|
+
if ("assistant" === message.role) {
|
|
190
|
+
if ("number" == typeof message.createdAt && !(message.createdAt < invocationStartedAt - windowMs)) {
|
|
191
|
+
if ("string" == typeof message.content && message.content.trim()) return message.content;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
};
|
|
91
196
|
class AgentInvoker {
|
|
92
197
|
findAllAgents() {
|
|
93
198
|
const agentConfigs = this.loader.loadAllAgentConfigs();
|
|
@@ -97,7 +202,11 @@ class AgentInvoker {
|
|
|
97
202
|
return await this.loader.loadAgent(name);
|
|
98
203
|
}
|
|
99
204
|
async invokeAgent(agentName, prompt, sessionId, attachments, options) {
|
|
205
|
+
const invocationStartedAt = Date.now();
|
|
100
206
|
let cancellationHandled = false;
|
|
207
|
+
let activeToolName = null;
|
|
208
|
+
let lastToolName = null;
|
|
209
|
+
let sawAssistantText = false;
|
|
101
210
|
const isCancelled = ()=>options?.signal?.aborted === true;
|
|
102
211
|
try {
|
|
103
212
|
const executionWorkspace = resolveExecutionWorkspace(this.workspace, this.workdir);
|
|
@@ -147,6 +256,29 @@ class AgentInvoker {
|
|
|
147
256
|
skillsDirectory
|
|
148
257
|
})
|
|
149
258
|
];
|
|
259
|
+
const summarizationSettings = resolveSummarizationMiddlewareSettings(this.wingmanConfig);
|
|
260
|
+
const modelRetrySettings = resolveModelRetryMiddlewareSettings(this.wingmanConfig);
|
|
261
|
+
if (modelRetrySettings) middleware.push((0, external_langchain_namespaceObject.modelRetryMiddleware)({
|
|
262
|
+
maxRetries: modelRetrySettings.maxRetries,
|
|
263
|
+
backoffFactor: modelRetrySettings.backoffFactor,
|
|
264
|
+
initialDelayMs: modelRetrySettings.initialDelayMs,
|
|
265
|
+
maxDelayMs: modelRetrySettings.maxDelayMs,
|
|
266
|
+
jitter: modelRetrySettings.jitter,
|
|
267
|
+
onFailure: modelRetrySettings.onFailure
|
|
268
|
+
}));
|
|
269
|
+
const toolRetrySettings = resolveToolRetryMiddlewareSettings(this.wingmanConfig);
|
|
270
|
+
if (toolRetrySettings) middleware.push((0, external_langchain_namespaceObject.toolRetryMiddleware)({
|
|
271
|
+
maxRetries: toolRetrySettings.maxRetries,
|
|
272
|
+
backoffFactor: toolRetrySettings.backoffFactor,
|
|
273
|
+
initialDelayMs: toolRetrySettings.initialDelayMs,
|
|
274
|
+
maxDelayMs: toolRetrySettings.maxDelayMs,
|
|
275
|
+
jitter: toolRetrySettings.jitter,
|
|
276
|
+
onFailure: toolRetrySettings.onFailure,
|
|
277
|
+
...toolRetrySettings.tools ? {
|
|
278
|
+
tools: toolRetrySettings.tools
|
|
279
|
+
} : {}
|
|
280
|
+
}));
|
|
281
|
+
const hitlSettings = resolveHumanInTheLoopSettings(this.wingmanConfig);
|
|
150
282
|
if (mergedHooks) {
|
|
151
283
|
this.logger.debug(`Adding hooks middleware with ${mergedHooks.PreToolUse?.length || 0} PreToolUse hooks, ${mergedHooks.PostToolUse?.length || 0} PostToolUse hooks, and ${mergedHooks.Stop?.length || 0} Stop hooks`);
|
|
152
284
|
middleware.push((0, hooks_cjs_namespaceObject.createHooksMiddleware)(mergedHooks, executionWorkspace, hookSessionId, this.logger));
|
|
@@ -193,10 +325,12 @@ class AgentInvoker {
|
|
|
193
325
|
virtualMode: true
|
|
194
326
|
}), backendOverrides),
|
|
195
327
|
middleware: middleware,
|
|
328
|
+
interruptOn: hitlSettings?.interruptOn,
|
|
196
329
|
skills: skillsSources,
|
|
197
330
|
subagents: targetAgent.subagents || [],
|
|
198
331
|
checkpointer: checkpointer
|
|
199
332
|
});
|
|
333
|
+
configureDeepAgentSummarizationMiddleware(standaloneAgent, summarizationSettings, targetAgent.model);
|
|
200
334
|
this.logger.debug("Agent created, sending message");
|
|
201
335
|
const userContent = buildUserContent(prompt, attachments, targetAgent.model);
|
|
202
336
|
if (this.sessionManager && sessionId) {
|
|
@@ -217,6 +351,13 @@ class AgentInvoker {
|
|
|
217
351
|
signal: options?.signal
|
|
218
352
|
});
|
|
219
353
|
for await (const chunk of stream){
|
|
354
|
+
if (!sawAssistantText && chunkHasAssistantText(chunk)) sawAssistantText = true;
|
|
355
|
+
const toolEvent = detectToolEventContext(chunk);
|
|
356
|
+
if (toolEvent) {
|
|
357
|
+
lastToolName = toolEvent.toolName;
|
|
358
|
+
if ("on_tool_start" === toolEvent.event) activeToolName = toolEvent.toolName;
|
|
359
|
+
else if (activeToolName === toolEvent.toolName) activeToolName = null;
|
|
360
|
+
}
|
|
220
361
|
if (isCancelled()) {
|
|
221
362
|
cancellationHandled = true;
|
|
222
363
|
this.logger.info("Agent invocation cancelled");
|
|
@@ -237,8 +378,27 @@ class AgentInvoker {
|
|
|
237
378
|
};
|
|
238
379
|
}
|
|
239
380
|
this.logger.info("Agent streaming completed successfully");
|
|
381
|
+
let fallbackText;
|
|
382
|
+
if (!sawAssistantText && this.sessionManager && sessionId) try {
|
|
383
|
+
const sessionMessages = await this.sessionManager.listMessages(sessionId);
|
|
384
|
+
fallbackText = selectStreamingFallbackText(sessionMessages, invocationStartedAt);
|
|
385
|
+
} catch (stateError) {
|
|
386
|
+
this.logger.debug("Failed to derive streaming fallback text from session state", stateError);
|
|
387
|
+
}
|
|
388
|
+
if (!sawAssistantText && !fallbackText) {
|
|
389
|
+
const emptyResponseMessage = "Model completed without a response. Check provider logs for request errors.";
|
|
390
|
+
this.logger.warn(emptyResponseMessage);
|
|
391
|
+
this.outputManager.emitAgentError(emptyResponseMessage);
|
|
392
|
+
return {
|
|
393
|
+
blocked: true,
|
|
394
|
+
reason: "empty_stream_response"
|
|
395
|
+
};
|
|
396
|
+
}
|
|
240
397
|
this.outputManager.emitAgentComplete({
|
|
241
|
-
streaming: true
|
|
398
|
+
streaming: true,
|
|
399
|
+
...fallbackText ? {
|
|
400
|
+
fallbackText
|
|
401
|
+
} : {}
|
|
242
402
|
});
|
|
243
403
|
return {
|
|
244
404
|
streaming: true
|
|
@@ -286,8 +446,10 @@ class AgentInvoker {
|
|
|
286
446
|
cancelled: true
|
|
287
447
|
};
|
|
288
448
|
}
|
|
289
|
-
this.logger.error(`Agent invocation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
290
|
-
|
|
449
|
+
this.logger.error(`Agent invocation failed: ${error instanceof Error ? error.message : String(error)}${activeToolName ? ` (while running tool "${activeToolName}")` : lastToolName ? ` (last tool: "${lastToolName}")` : ""}`);
|
|
450
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
451
|
+
const errorWithToolContext = activeToolName ? `${errorMessage} (while running tool "${activeToolName}")` : lastToolName ? `${errorMessage} (last tool: "${lastToolName}")` : errorMessage;
|
|
452
|
+
this.outputManager.emitAgentError(errorWithToolContext);
|
|
291
453
|
throw error;
|
|
292
454
|
} finally{
|
|
293
455
|
if (this.mcpManager) {
|
|
@@ -516,16 +678,32 @@ exports.AgentInvoker = __webpack_exports__.AgentInvoker;
|
|
|
516
678
|
exports.OUTPUT_VIRTUAL_PATH = __webpack_exports__.OUTPUT_VIRTUAL_PATH;
|
|
517
679
|
exports.WORKDIR_VIRTUAL_PATH = __webpack_exports__.WORKDIR_VIRTUAL_PATH;
|
|
518
680
|
exports.buildUserContent = __webpack_exports__.buildUserContent;
|
|
681
|
+
exports.chunkHasAssistantText = __webpack_exports__.chunkHasAssistantText;
|
|
682
|
+
exports.configureDeepAgentSummarizationMiddleware = __webpack_exports__.configureDeepAgentSummarizationMiddleware;
|
|
683
|
+
exports.detectToolEventContext = __webpack_exports__.detectToolEventContext;
|
|
519
684
|
exports.resolveExecutionWorkspace = __webpack_exports__.resolveExecutionWorkspace;
|
|
520
685
|
exports.resolveExternalOutputMount = __webpack_exports__.resolveExternalOutputMount;
|
|
686
|
+
exports.resolveHumanInTheLoopSettings = __webpack_exports__.resolveHumanInTheLoopSettings;
|
|
687
|
+
exports.resolveModelRetryMiddlewareSettings = __webpack_exports__.resolveModelRetryMiddlewareSettings;
|
|
688
|
+
exports.resolveSummarizationMiddlewareSettings = __webpack_exports__.resolveSummarizationMiddlewareSettings;
|
|
689
|
+
exports.resolveToolRetryMiddlewareSettings = __webpack_exports__.resolveToolRetryMiddlewareSettings;
|
|
690
|
+
exports.selectStreamingFallbackText = __webpack_exports__.selectStreamingFallbackText;
|
|
521
691
|
exports.toWorkspaceAliasVirtualPath = __webpack_exports__.toWorkspaceAliasVirtualPath;
|
|
522
692
|
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
523
693
|
"AgentInvoker",
|
|
524
694
|
"OUTPUT_VIRTUAL_PATH",
|
|
525
695
|
"WORKDIR_VIRTUAL_PATH",
|
|
526
696
|
"buildUserContent",
|
|
697
|
+
"chunkHasAssistantText",
|
|
698
|
+
"configureDeepAgentSummarizationMiddleware",
|
|
699
|
+
"detectToolEventContext",
|
|
527
700
|
"resolveExecutionWorkspace",
|
|
528
701
|
"resolveExternalOutputMount",
|
|
702
|
+
"resolveHumanInTheLoopSettings",
|
|
703
|
+
"resolveModelRetryMiddlewareSettings",
|
|
704
|
+
"resolveSummarizationMiddlewareSettings",
|
|
705
|
+
"resolveToolRetryMiddlewareSettings",
|
|
706
|
+
"selectStreamingFallbackText",
|
|
529
707
|
"toWorkspaceAliasVirtualPath"
|
|
530
708
|
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
531
709
|
Object.defineProperty(exports, '__esModule', {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type { OutputManager } from "./outputManager.js";
|
|
2
|
-
import type { Logger } from "../../logger.js";
|
|
3
1
|
import type { WingmanAgentConfig } from "@/agent/config/agentConfig.js";
|
|
4
2
|
import type { WingmanAgent } from "@/types/agents.js";
|
|
5
|
-
import {
|
|
3
|
+
import type { Logger } from "../../logger.js";
|
|
4
|
+
import type { WingmanConfigType } from "../config/schema.js";
|
|
5
|
+
import type { OutputManager } from "./outputManager.js";
|
|
6
|
+
import type { SessionManager } from "./sessionManager.js";
|
|
6
7
|
export interface AgentInvokerOptions {
|
|
7
8
|
workspace?: string;
|
|
8
9
|
configDir?: string;
|
|
@@ -79,9 +80,47 @@ export type ExternalOutputMount = {
|
|
|
79
80
|
virtualPath: string | null;
|
|
80
81
|
absolutePath: string | null;
|
|
81
82
|
};
|
|
83
|
+
export type SummarizationMiddlewareSettings = {
|
|
84
|
+
maxTokensBeforeSummary: number;
|
|
85
|
+
messagesToKeep: number;
|
|
86
|
+
};
|
|
87
|
+
export type ModelRetryMiddlewareSettings = {
|
|
88
|
+
maxRetries: number;
|
|
89
|
+
backoffFactor: number;
|
|
90
|
+
initialDelayMs: number;
|
|
91
|
+
maxDelayMs: number;
|
|
92
|
+
jitter: boolean;
|
|
93
|
+
onFailure: "continue" | "error";
|
|
94
|
+
};
|
|
95
|
+
export type ToolRetryMiddlewareSettings = ModelRetryMiddlewareSettings & {
|
|
96
|
+
tools?: string[];
|
|
97
|
+
};
|
|
98
|
+
export type HumanInTheLoopSettings = {
|
|
99
|
+
interruptOn: Record<string, boolean | {
|
|
100
|
+
allowedDecisions: Array<"approve" | "edit" | "reject">;
|
|
101
|
+
description?: string;
|
|
102
|
+
argsSchema?: Record<string, any>;
|
|
103
|
+
}>;
|
|
104
|
+
};
|
|
82
105
|
export declare const resolveExecutionWorkspace: (workspace: string, workdir?: string | null) => string;
|
|
83
106
|
export declare const toWorkspaceAliasVirtualPath: (absolutePath: string) => string | null;
|
|
84
107
|
export declare const resolveExternalOutputMount: (workspace: string, workdir?: string | null, defaultOutputDir?: string | null) => ExternalOutputMount;
|
|
108
|
+
export declare const resolveSummarizationMiddlewareSettings: (config: WingmanConfigType) => SummarizationMiddlewareSettings | null;
|
|
109
|
+
export declare const resolveModelRetryMiddlewareSettings: (config: WingmanConfigType) => ModelRetryMiddlewareSettings | null;
|
|
110
|
+
export declare const resolveToolRetryMiddlewareSettings: (config: WingmanConfigType) => ToolRetryMiddlewareSettings | null;
|
|
111
|
+
export declare const resolveHumanInTheLoopSettings: (config: WingmanConfigType) => HumanInTheLoopSettings | null;
|
|
112
|
+
export declare const configureDeepAgentSummarizationMiddleware: (agent: any, settings: SummarizationMiddlewareSettings | null, model?: any) => void;
|
|
113
|
+
type ToolEventContext = {
|
|
114
|
+
event: "on_tool_start" | "on_tool_end";
|
|
115
|
+
toolName: string;
|
|
116
|
+
};
|
|
117
|
+
export declare const detectToolEventContext: (chunk: unknown) => ToolEventContext | null;
|
|
118
|
+
export declare const chunkHasAssistantText: (chunk: unknown) => boolean;
|
|
119
|
+
export declare const selectStreamingFallbackText: (sessionMessages: Array<{
|
|
120
|
+
role?: unknown;
|
|
121
|
+
createdAt?: unknown;
|
|
122
|
+
content?: unknown;
|
|
123
|
+
}>, invocationStartedAt: number, windowMs?: number) => string | undefined;
|
|
85
124
|
export declare class AgentInvoker {
|
|
86
125
|
private loader;
|
|
87
126
|
private outputManager;
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { CompositeBackend, FilesystemBackend, createDeepAgent } from "deepagents";
|
|
2
1
|
import { existsSync } from "node:fs";
|
|
3
2
|
import { isAbsolute, join, normalize, sep } from "node:path";
|
|
3
|
+
import { CompositeBackend, FilesystemBackend, createDeepAgent } from "deepagents";
|
|
4
|
+
import { modelRetryMiddleware, summarizationMiddleware, toolRetryMiddleware } from "langchain";
|
|
4
5
|
import { v4 } from "uuid";
|
|
5
|
-
import {
|
|
6
|
-
import { WingmanConfigLoader } from "../config/loader.js";
|
|
6
|
+
import { MCPClientManager } from "../../agent/config/mcpClientManager.js";
|
|
7
7
|
import { additionalMessageMiddleware } from "../../agent/middleware/additional-messages.js";
|
|
8
|
-
import { createHooksMiddleware } from "../../agent/middleware/hooks.js";
|
|
9
8
|
import { mergeHooks } from "../../agent/middleware/hooks/merger.js";
|
|
9
|
+
import { createHooksMiddleware } from "../../agent/middleware/hooks.js";
|
|
10
10
|
import { mediaCompatibilityMiddleware } from "../../agent/middleware/media-compat.js";
|
|
11
|
-
import { MCPClientManager } from "../../agent/config/mcpClientManager.js";
|
|
12
11
|
import { getBundledSkillsPath } from "../../agent/uiRegistry.js";
|
|
12
|
+
import { AgentLoader } from "../../agent/config/agentLoader.js";
|
|
13
|
+
import { WingmanConfigLoader } from "../config/loader.js";
|
|
13
14
|
function _define_property(obj, key, value) {
|
|
14
15
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
15
16
|
value: value,
|
|
@@ -22,6 +23,7 @@ function _define_property(obj, key, value) {
|
|
|
22
23
|
}
|
|
23
24
|
const WORKDIR_VIRTUAL_PATH = "/workdir/";
|
|
24
25
|
const OUTPUT_VIRTUAL_PATH = "/output/";
|
|
26
|
+
const DEFAULT_DEEPAGENT_MODEL = "claude-sonnet-4-5-20250929";
|
|
25
27
|
const isPathWithinRoot = (targetPath, rootPath)=>{
|
|
26
28
|
const normalizedTarget = normalize(targetPath);
|
|
27
29
|
const normalizedRoot = normalize(rootPath);
|
|
@@ -54,6 +56,101 @@ const resolveExternalOutputMount = (workspace, workdir, defaultOutputDir)=>{
|
|
|
54
56
|
absolutePath: null
|
|
55
57
|
};
|
|
56
58
|
};
|
|
59
|
+
const resolveSummarizationMiddlewareSettings = (config)=>{
|
|
60
|
+
if (!config.summarization?.enabled) return null;
|
|
61
|
+
return {
|
|
62
|
+
maxTokensBeforeSummary: config.summarization.maxTokensBeforeSummary,
|
|
63
|
+
messagesToKeep: config.summarization.messagesToKeep
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
const resolveModelRetryMiddlewareSettings = (config)=>{
|
|
67
|
+
if (!config.modelRetry?.enabled) return null;
|
|
68
|
+
return {
|
|
69
|
+
maxRetries: config.modelRetry.maxRetries,
|
|
70
|
+
backoffFactor: config.modelRetry.backoffFactor,
|
|
71
|
+
initialDelayMs: config.modelRetry.initialDelayMs,
|
|
72
|
+
maxDelayMs: config.modelRetry.maxDelayMs,
|
|
73
|
+
jitter: config.modelRetry.jitter,
|
|
74
|
+
onFailure: config.modelRetry.onFailure
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
const resolveToolRetryMiddlewareSettings = (config)=>{
|
|
78
|
+
if (!config.toolRetry?.enabled) return null;
|
|
79
|
+
return {
|
|
80
|
+
maxRetries: config.toolRetry.maxRetries,
|
|
81
|
+
backoffFactor: config.toolRetry.backoffFactor,
|
|
82
|
+
initialDelayMs: config.toolRetry.initialDelayMs,
|
|
83
|
+
maxDelayMs: config.toolRetry.maxDelayMs,
|
|
84
|
+
jitter: config.toolRetry.jitter,
|
|
85
|
+
onFailure: config.toolRetry.onFailure,
|
|
86
|
+
...config.toolRetry.tools && config.toolRetry.tools.length > 0 ? {
|
|
87
|
+
tools: config.toolRetry.tools
|
|
88
|
+
} : {}
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
const resolveHumanInTheLoopSettings = (config)=>{
|
|
92
|
+
if (!config.humanInTheLoop?.enabled) return null;
|
|
93
|
+
const interruptOn = config.humanInTheLoop.interruptOn || {};
|
|
94
|
+
if (0 === Object.keys(interruptOn).length) return null;
|
|
95
|
+
return {
|
|
96
|
+
interruptOn
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
const configureDeepAgentSummarizationMiddleware = (agent, settings, model)=>{
|
|
100
|
+
const middleware = agent?.options?.middleware;
|
|
101
|
+
if (!Array.isArray(middleware)) return;
|
|
102
|
+
const index = middleware.findIndex((entry)=>entry?.name === "SummarizationMiddleware");
|
|
103
|
+
if (index < 0) return;
|
|
104
|
+
if (!settings) return void middleware.splice(index, 1);
|
|
105
|
+
middleware[index] = summarizationMiddleware({
|
|
106
|
+
model: model || DEFAULT_DEEPAGENT_MODEL,
|
|
107
|
+
trigger: {
|
|
108
|
+
tokens: settings.maxTokensBeforeSummary
|
|
109
|
+
},
|
|
110
|
+
keep: {
|
|
111
|
+
messages: settings.messagesToKeep
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
const detectToolEventContext = (chunk)=>{
|
|
116
|
+
if (!chunk || "object" != typeof chunk || Array.isArray(chunk)) return null;
|
|
117
|
+
const eventChunk = chunk;
|
|
118
|
+
if ("on_tool_start" !== eventChunk.event && "on_tool_end" !== eventChunk.event) return null;
|
|
119
|
+
const toolName = "string" == typeof eventChunk.name && eventChunk.name.trim() ? eventChunk.name.trim() : "unknown";
|
|
120
|
+
return {
|
|
121
|
+
event: eventChunk.event,
|
|
122
|
+
toolName
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
const chunkHasAssistantText = (chunk)=>{
|
|
126
|
+
if (!chunk || "object" != typeof chunk || Array.isArray(chunk)) return false;
|
|
127
|
+
const eventChunk = chunk;
|
|
128
|
+
const eventName = "string" == typeof eventChunk.event ? eventChunk.event : void 0;
|
|
129
|
+
if ("on_chat_model_stream" === eventName) {
|
|
130
|
+
const data = eventChunk.data && "object" == typeof eventChunk.data ? eventChunk.data : null;
|
|
131
|
+
const messageChunk = data?.chunk || data?.message;
|
|
132
|
+
const content = messageChunk?.content;
|
|
133
|
+
if ("string" == typeof content) return content.length > 0;
|
|
134
|
+
if (Array.isArray(content)) return content.some((part)=>part && "object" == typeof part && "text" === part.type && "string" == typeof part.text && part.text.length > 0);
|
|
135
|
+
}
|
|
136
|
+
if ("on_llm_stream" === eventName) {
|
|
137
|
+
const data = eventChunk.data && "object" == typeof eventChunk.data ? eventChunk.data : null;
|
|
138
|
+
const llmChunk = data?.chunk && "object" == typeof data.chunk ? data.chunk : null;
|
|
139
|
+
return "string" == typeof llmChunk?.text && llmChunk.text.length > 0;
|
|
140
|
+
}
|
|
141
|
+
return false;
|
|
142
|
+
};
|
|
143
|
+
const selectStreamingFallbackText = (sessionMessages, invocationStartedAt, windowMs = 1000)=>{
|
|
144
|
+
for(let i = sessionMessages.length - 1; i >= 0; i -= 1){
|
|
145
|
+
const message = sessionMessages[i];
|
|
146
|
+
if (!message || "object" != typeof message) continue;
|
|
147
|
+
if ("assistant" === message.role) {
|
|
148
|
+
if ("number" == typeof message.createdAt && !(message.createdAt < invocationStartedAt - windowMs)) {
|
|
149
|
+
if ("string" == typeof message.content && message.content.trim()) return message.content;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
};
|
|
57
154
|
class AgentInvoker {
|
|
58
155
|
findAllAgents() {
|
|
59
156
|
const agentConfigs = this.loader.loadAllAgentConfigs();
|
|
@@ -63,7 +160,11 @@ class AgentInvoker {
|
|
|
63
160
|
return await this.loader.loadAgent(name);
|
|
64
161
|
}
|
|
65
162
|
async invokeAgent(agentName, prompt, sessionId, attachments, options) {
|
|
163
|
+
const invocationStartedAt = Date.now();
|
|
66
164
|
let cancellationHandled = false;
|
|
165
|
+
let activeToolName = null;
|
|
166
|
+
let lastToolName = null;
|
|
167
|
+
let sawAssistantText = false;
|
|
67
168
|
const isCancelled = ()=>options?.signal?.aborted === true;
|
|
68
169
|
try {
|
|
69
170
|
const executionWorkspace = resolveExecutionWorkspace(this.workspace, this.workdir);
|
|
@@ -113,6 +214,29 @@ class AgentInvoker {
|
|
|
113
214
|
skillsDirectory
|
|
114
215
|
})
|
|
115
216
|
];
|
|
217
|
+
const summarizationSettings = resolveSummarizationMiddlewareSettings(this.wingmanConfig);
|
|
218
|
+
const modelRetrySettings = resolveModelRetryMiddlewareSettings(this.wingmanConfig);
|
|
219
|
+
if (modelRetrySettings) middleware.push(modelRetryMiddleware({
|
|
220
|
+
maxRetries: modelRetrySettings.maxRetries,
|
|
221
|
+
backoffFactor: modelRetrySettings.backoffFactor,
|
|
222
|
+
initialDelayMs: modelRetrySettings.initialDelayMs,
|
|
223
|
+
maxDelayMs: modelRetrySettings.maxDelayMs,
|
|
224
|
+
jitter: modelRetrySettings.jitter,
|
|
225
|
+
onFailure: modelRetrySettings.onFailure
|
|
226
|
+
}));
|
|
227
|
+
const toolRetrySettings = resolveToolRetryMiddlewareSettings(this.wingmanConfig);
|
|
228
|
+
if (toolRetrySettings) middleware.push(toolRetryMiddleware({
|
|
229
|
+
maxRetries: toolRetrySettings.maxRetries,
|
|
230
|
+
backoffFactor: toolRetrySettings.backoffFactor,
|
|
231
|
+
initialDelayMs: toolRetrySettings.initialDelayMs,
|
|
232
|
+
maxDelayMs: toolRetrySettings.maxDelayMs,
|
|
233
|
+
jitter: toolRetrySettings.jitter,
|
|
234
|
+
onFailure: toolRetrySettings.onFailure,
|
|
235
|
+
...toolRetrySettings.tools ? {
|
|
236
|
+
tools: toolRetrySettings.tools
|
|
237
|
+
} : {}
|
|
238
|
+
}));
|
|
239
|
+
const hitlSettings = resolveHumanInTheLoopSettings(this.wingmanConfig);
|
|
116
240
|
if (mergedHooks) {
|
|
117
241
|
this.logger.debug(`Adding hooks middleware with ${mergedHooks.PreToolUse?.length || 0} PreToolUse hooks, ${mergedHooks.PostToolUse?.length || 0} PostToolUse hooks, and ${mergedHooks.Stop?.length || 0} Stop hooks`);
|
|
118
242
|
middleware.push(createHooksMiddleware(mergedHooks, executionWorkspace, hookSessionId, this.logger));
|
|
@@ -159,10 +283,12 @@ class AgentInvoker {
|
|
|
159
283
|
virtualMode: true
|
|
160
284
|
}), backendOverrides),
|
|
161
285
|
middleware: middleware,
|
|
286
|
+
interruptOn: hitlSettings?.interruptOn,
|
|
162
287
|
skills: skillsSources,
|
|
163
288
|
subagents: targetAgent.subagents || [],
|
|
164
289
|
checkpointer: checkpointer
|
|
165
290
|
});
|
|
291
|
+
configureDeepAgentSummarizationMiddleware(standaloneAgent, summarizationSettings, targetAgent.model);
|
|
166
292
|
this.logger.debug("Agent created, sending message");
|
|
167
293
|
const userContent = buildUserContent(prompt, attachments, targetAgent.model);
|
|
168
294
|
if (this.sessionManager && sessionId) {
|
|
@@ -183,6 +309,13 @@ class AgentInvoker {
|
|
|
183
309
|
signal: options?.signal
|
|
184
310
|
});
|
|
185
311
|
for await (const chunk of stream){
|
|
312
|
+
if (!sawAssistantText && chunkHasAssistantText(chunk)) sawAssistantText = true;
|
|
313
|
+
const toolEvent = detectToolEventContext(chunk);
|
|
314
|
+
if (toolEvent) {
|
|
315
|
+
lastToolName = toolEvent.toolName;
|
|
316
|
+
if ("on_tool_start" === toolEvent.event) activeToolName = toolEvent.toolName;
|
|
317
|
+
else if (activeToolName === toolEvent.toolName) activeToolName = null;
|
|
318
|
+
}
|
|
186
319
|
if (isCancelled()) {
|
|
187
320
|
cancellationHandled = true;
|
|
188
321
|
this.logger.info("Agent invocation cancelled");
|
|
@@ -203,8 +336,27 @@ class AgentInvoker {
|
|
|
203
336
|
};
|
|
204
337
|
}
|
|
205
338
|
this.logger.info("Agent streaming completed successfully");
|
|
339
|
+
let fallbackText;
|
|
340
|
+
if (!sawAssistantText && this.sessionManager && sessionId) try {
|
|
341
|
+
const sessionMessages = await this.sessionManager.listMessages(sessionId);
|
|
342
|
+
fallbackText = selectStreamingFallbackText(sessionMessages, invocationStartedAt);
|
|
343
|
+
} catch (stateError) {
|
|
344
|
+
this.logger.debug("Failed to derive streaming fallback text from session state", stateError);
|
|
345
|
+
}
|
|
346
|
+
if (!sawAssistantText && !fallbackText) {
|
|
347
|
+
const emptyResponseMessage = "Model completed without a response. Check provider logs for request errors.";
|
|
348
|
+
this.logger.warn(emptyResponseMessage);
|
|
349
|
+
this.outputManager.emitAgentError(emptyResponseMessage);
|
|
350
|
+
return {
|
|
351
|
+
blocked: true,
|
|
352
|
+
reason: "empty_stream_response"
|
|
353
|
+
};
|
|
354
|
+
}
|
|
206
355
|
this.outputManager.emitAgentComplete({
|
|
207
|
-
streaming: true
|
|
356
|
+
streaming: true,
|
|
357
|
+
...fallbackText ? {
|
|
358
|
+
fallbackText
|
|
359
|
+
} : {}
|
|
208
360
|
});
|
|
209
361
|
return {
|
|
210
362
|
streaming: true
|
|
@@ -252,8 +404,10 @@ class AgentInvoker {
|
|
|
252
404
|
cancelled: true
|
|
253
405
|
};
|
|
254
406
|
}
|
|
255
|
-
this.logger.error(`Agent invocation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
256
|
-
|
|
407
|
+
this.logger.error(`Agent invocation failed: ${error instanceof Error ? error.message : String(error)}${activeToolName ? ` (while running tool "${activeToolName}")` : lastToolName ? ` (last tool: "${lastToolName}")` : ""}`);
|
|
408
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
409
|
+
const errorWithToolContext = activeToolName ? `${errorMessage} (while running tool "${activeToolName}")` : lastToolName ? `${errorMessage} (last tool: "${lastToolName}")` : errorMessage;
|
|
410
|
+
this.outputManager.emitAgentError(errorWithToolContext);
|
|
257
411
|
throw error;
|
|
258
412
|
} finally{
|
|
259
413
|
if (this.mcpManager) {
|
|
@@ -478,4 +632,4 @@ function buildAttachmentPreview(attachments) {
|
|
|
478
632
|
if (hasImage) return "[image]";
|
|
479
633
|
return "";
|
|
480
634
|
}
|
|
481
|
-
export { AgentInvoker, OUTPUT_VIRTUAL_PATH, WORKDIR_VIRTUAL_PATH, buildUserContent, resolveExecutionWorkspace, resolveExternalOutputMount, toWorkspaceAliasVirtualPath };
|
|
635
|
+
export { AgentInvoker, OUTPUT_VIRTUAL_PATH, WORKDIR_VIRTUAL_PATH, buildUserContent, chunkHasAssistantText, configureDeepAgentSummarizationMiddleware, detectToolEventContext, resolveExecutionWorkspace, resolveExternalOutputMount, resolveHumanInTheLoopSettings, resolveModelRetryMiddlewareSettings, resolveSummarizationMiddlewareSettings, resolveToolRetryMiddlewareSettings, selectStreamingFallbackText, toWorkspaceAliasVirtualPath };
|
|
@@ -68,6 +68,8 @@ class SessionManager {
|
|
|
68
68
|
|
|
69
69
|
CREATE INDEX IF NOT EXISTS idx_sessions_updated ON sessions(updated_at DESC);
|
|
70
70
|
CREATE INDEX IF NOT EXISTS idx_sessions_agent ON sessions(agent_name);
|
|
71
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_status_updated ON sessions(status, updated_at DESC);
|
|
72
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_status_agent_updated ON sessions(status, agent_name, updated_at DESC);
|
|
71
73
|
`);
|
|
72
74
|
}
|
|
73
75
|
createSession(agentName, name) {
|
|
@@ -407,13 +409,38 @@ function extractContentBlocks(entry) {
|
|
|
407
409
|
}
|
|
408
410
|
function extractMessageContent(entry, blocks = []) {
|
|
409
411
|
if (!entry || "object" != typeof entry) return "";
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
412
|
+
const candidates = [
|
|
413
|
+
entry.content,
|
|
414
|
+
entry?.kwargs?.content,
|
|
415
|
+
entry?.additional_kwargs?.content,
|
|
416
|
+
entry?.data?.content
|
|
417
|
+
];
|
|
418
|
+
for (const candidate of candidates){
|
|
419
|
+
const extracted = extractTextContent(candidate);
|
|
420
|
+
if (extracted) return extracted;
|
|
421
|
+
}
|
|
422
|
+
if (blocks.length > 0) return extractTextContent(blocks);
|
|
423
|
+
return "";
|
|
424
|
+
}
|
|
425
|
+
function extractTextContent(value, depth = 0) {
|
|
426
|
+
if (depth > 5 || null == value) return "";
|
|
427
|
+
if ("string" == typeof value) return value;
|
|
428
|
+
if (Array.isArray(value)) return value.map((entry)=>extractTextContent(entry, depth + 1)).filter((entry)=>entry.length > 0).join("");
|
|
429
|
+
if ("object" != typeof value) return "";
|
|
430
|
+
const record = value;
|
|
431
|
+
if ("string" == typeof record.text) return record.text;
|
|
432
|
+
if (record.text && "object" == typeof record.text && "string" == typeof record.text.value) return record.text.value;
|
|
433
|
+
if ("string" == typeof record.output_text) return record.output_text;
|
|
434
|
+
if ("string" == typeof record.input_text) return record.input_text;
|
|
435
|
+
if ("string" == typeof record.value && isTextLikeContentType(record.type)) return record.value;
|
|
436
|
+
if ("content" in record) return extractTextContent(record.content, depth + 1);
|
|
415
437
|
return "";
|
|
416
438
|
}
|
|
439
|
+
function isTextLikeContentType(type) {
|
|
440
|
+
if ("string" != typeof type) return false;
|
|
441
|
+
const normalized = type.toLowerCase();
|
|
442
|
+
return "text" === normalized || "input_text" === normalized || "output_text" === normalized || "text_delta" === normalized;
|
|
443
|
+
}
|
|
417
444
|
function isToolMessage(entry) {
|
|
418
445
|
if (!entry || "object" != typeof entry) return false;
|
|
419
446
|
const role = entry.role || entry?.kwargs?.role || entry?.additional_kwargs?.role;
|