@wingman-ai/gateway 0.2.1 → 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/README.md +1 -0
- package/.wingman/agents/coding/agent.md +179 -112
- package/.wingman/agents/coding/implementor.md +50 -3
- package/.wingman/agents/main/agent.md +4 -0
- package/README.md +1 -0
- package/dist/agent/config/agentConfig.cjs +30 -1
- package/dist/agent/config/agentConfig.js +30 -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/agentConfig.test.cjs +39 -0
- package/dist/agent/tests/agentConfig.test.js +39 -0
- 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 +242 -17
- package/dist/cli/core/agentInvoker.d.ts +46 -4
- package/dist/cli/core/agentInvoker.js +214 -13
- 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 +230 -28
- package/dist/gateway/server.d.ts +11 -1
- package/dist/gateway/server.js +230 -28
- package/dist/gateway/types.d.ts +5 -1
- package/dist/gateway/validation.cjs +1 -0
- package/dist/gateway/validation.d.ts +2 -0
- package/dist/gateway/validation.js +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 +173 -1
- package/dist/tests/gateway.test.js +173 -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-BVMavpud.css +11 -0
- package/dist/webui/assets/index-DCB2aVVf.js +182 -0
- package/dist/webui/index.html +2 -2
- package/package.json +3 -1
- package/dist/webui/assets/index-BytPznA_.css +0 -1
- package/dist/webui/assets/index-u_5qlVip.js +0 -176
|
@@ -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();
|
|
@@ -62,7 +159,13 @@ class AgentInvoker {
|
|
|
62
159
|
async findAgent(name) {
|
|
63
160
|
return await this.loader.loadAgent(name);
|
|
64
161
|
}
|
|
65
|
-
async invokeAgent(agentName, prompt, sessionId, attachments) {
|
|
162
|
+
async invokeAgent(agentName, prompt, sessionId, attachments, options) {
|
|
163
|
+
const invocationStartedAt = Date.now();
|
|
164
|
+
let cancellationHandled = false;
|
|
165
|
+
let activeToolName = null;
|
|
166
|
+
let lastToolName = null;
|
|
167
|
+
let sawAssistantText = false;
|
|
168
|
+
const isCancelled = ()=>options?.signal?.aborted === true;
|
|
66
169
|
try {
|
|
67
170
|
const executionWorkspace = resolveExecutionWorkspace(this.workspace, this.workdir);
|
|
68
171
|
const effectiveWorkdir = this.workdir ? executionWorkspace : null;
|
|
@@ -111,6 +214,29 @@ class AgentInvoker {
|
|
|
111
214
|
skillsDirectory
|
|
112
215
|
})
|
|
113
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);
|
|
114
240
|
if (mergedHooks) {
|
|
115
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`);
|
|
116
242
|
middleware.push(createHooksMiddleware(mergedHooks, executionWorkspace, hookSessionId, this.logger));
|
|
@@ -157,10 +283,12 @@ class AgentInvoker {
|
|
|
157
283
|
virtualMode: true
|
|
158
284
|
}), backendOverrides),
|
|
159
285
|
middleware: middleware,
|
|
286
|
+
interruptOn: hitlSettings?.interruptOn,
|
|
160
287
|
skills: skillsSources,
|
|
161
288
|
subagents: targetAgent.subagents || [],
|
|
162
289
|
checkpointer: checkpointer
|
|
163
290
|
});
|
|
291
|
+
configureDeepAgentSummarizationMiddleware(standaloneAgent, summarizationSettings, targetAgent.model);
|
|
164
292
|
this.logger.debug("Agent created, sending message");
|
|
165
293
|
const userContent = buildUserContent(prompt, attachments, targetAgent.model);
|
|
166
294
|
if (this.sessionManager && sessionId) {
|
|
@@ -177,12 +305,58 @@ class AgentInvoker {
|
|
|
177
305
|
configurable: {
|
|
178
306
|
thread_id: sessionId
|
|
179
307
|
},
|
|
180
|
-
version: "v2"
|
|
308
|
+
version: "v2",
|
|
309
|
+
signal: options?.signal
|
|
181
310
|
});
|
|
182
|
-
for await (const chunk of stream)
|
|
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
|
+
}
|
|
319
|
+
if (isCancelled()) {
|
|
320
|
+
cancellationHandled = true;
|
|
321
|
+
this.logger.info("Agent invocation cancelled");
|
|
322
|
+
this.outputManager.emitAgentError("Request cancelled");
|
|
323
|
+
if ("function" == typeof stream?.return) await stream.return();
|
|
324
|
+
return {
|
|
325
|
+
cancelled: true
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
this.outputManager.emitAgentStream(chunk);
|
|
329
|
+
}
|
|
330
|
+
if (isCancelled()) {
|
|
331
|
+
cancellationHandled = true;
|
|
332
|
+
this.logger.info("Agent invocation cancelled");
|
|
333
|
+
this.outputManager.emitAgentError("Request cancelled");
|
|
334
|
+
return {
|
|
335
|
+
cancelled: true
|
|
336
|
+
};
|
|
337
|
+
}
|
|
183
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
|
+
}
|
|
184
355
|
this.outputManager.emitAgentComplete({
|
|
185
|
-
streaming: true
|
|
356
|
+
streaming: true,
|
|
357
|
+
...fallbackText ? {
|
|
358
|
+
fallbackText
|
|
359
|
+
} : {}
|
|
186
360
|
});
|
|
187
361
|
return {
|
|
188
362
|
streaming: true
|
|
@@ -190,6 +364,14 @@ class AgentInvoker {
|
|
|
190
364
|
}
|
|
191
365
|
{
|
|
192
366
|
this.logger.debug("Using blocking invoke (no session manager)");
|
|
367
|
+
if (isCancelled()) {
|
|
368
|
+
cancellationHandled = true;
|
|
369
|
+
this.logger.info("Agent invocation cancelled");
|
|
370
|
+
this.outputManager.emitAgentError("Request cancelled");
|
|
371
|
+
return {
|
|
372
|
+
cancelled: true
|
|
373
|
+
};
|
|
374
|
+
}
|
|
193
375
|
const result = await standaloneAgent.invoke({
|
|
194
376
|
messages: [
|
|
195
377
|
{
|
|
@@ -198,15 +380,34 @@ class AgentInvoker {
|
|
|
198
380
|
}
|
|
199
381
|
]
|
|
200
382
|
}, {
|
|
201
|
-
recursionLimit: this.wingmanConfig.recursionLimit
|
|
383
|
+
recursionLimit: this.wingmanConfig.recursionLimit,
|
|
384
|
+
signal: options?.signal
|
|
202
385
|
});
|
|
386
|
+
if (isCancelled()) {
|
|
387
|
+
cancellationHandled = true;
|
|
388
|
+
this.logger.info("Agent invocation cancelled");
|
|
389
|
+
this.outputManager.emitAgentError("Request cancelled");
|
|
390
|
+
return {
|
|
391
|
+
cancelled: true
|
|
392
|
+
};
|
|
393
|
+
}
|
|
203
394
|
this.logger.info("Agent completed successfully");
|
|
204
395
|
this.outputManager.emitAgentComplete(result);
|
|
205
396
|
return result;
|
|
206
397
|
}
|
|
207
398
|
} catch (error) {
|
|
208
|
-
|
|
209
|
-
|
|
399
|
+
const abortError = isCancelled() || error instanceof Error && ("AbortError" === error.name || "CancelledError" === error.name || /abort|cancel/i.test(error.message));
|
|
400
|
+
if (abortError) {
|
|
401
|
+
if (!cancellationHandled) this.outputManager.emitAgentError("Request cancelled");
|
|
402
|
+
this.logger.info("Agent invocation cancelled");
|
|
403
|
+
return {
|
|
404
|
+
cancelled: true
|
|
405
|
+
};
|
|
406
|
+
}
|
|
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);
|
|
210
411
|
throw error;
|
|
211
412
|
} finally{
|
|
212
413
|
if (this.mcpManager) {
|
|
@@ -431,4 +632,4 @@ function buildAttachmentPreview(attachments) {
|
|
|
431
632
|
if (hasImage) return "[image]";
|
|
432
633
|
return "";
|
|
433
634
|
}
|
|
434
|
-
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;
|
|
@@ -35,6 +35,8 @@ class SessionManager {
|
|
|
35
35
|
|
|
36
36
|
CREATE INDEX IF NOT EXISTS idx_sessions_updated ON sessions(updated_at DESC);
|
|
37
37
|
CREATE INDEX IF NOT EXISTS idx_sessions_agent ON sessions(agent_name);
|
|
38
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_status_updated ON sessions(status, updated_at DESC);
|
|
39
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_status_agent_updated ON sessions(status, agent_name, updated_at DESC);
|
|
38
40
|
`);
|
|
39
41
|
}
|
|
40
42
|
createSession(agentName, name) {
|
|
@@ -374,13 +376,38 @@ function extractContentBlocks(entry) {
|
|
|
374
376
|
}
|
|
375
377
|
function extractMessageContent(entry, blocks = []) {
|
|
376
378
|
if (!entry || "object" != typeof entry) return "";
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
379
|
+
const candidates = [
|
|
380
|
+
entry.content,
|
|
381
|
+
entry?.kwargs?.content,
|
|
382
|
+
entry?.additional_kwargs?.content,
|
|
383
|
+
entry?.data?.content
|
|
384
|
+
];
|
|
385
|
+
for (const candidate of candidates){
|
|
386
|
+
const extracted = extractTextContent(candidate);
|
|
387
|
+
if (extracted) return extracted;
|
|
388
|
+
}
|
|
389
|
+
if (blocks.length > 0) return extractTextContent(blocks);
|
|
390
|
+
return "";
|
|
391
|
+
}
|
|
392
|
+
function extractTextContent(value, depth = 0) {
|
|
393
|
+
if (depth > 5 || null == value) return "";
|
|
394
|
+
if ("string" == typeof value) return value;
|
|
395
|
+
if (Array.isArray(value)) return value.map((entry)=>extractTextContent(entry, depth + 1)).filter((entry)=>entry.length > 0).join("");
|
|
396
|
+
if ("object" != typeof value) return "";
|
|
397
|
+
const record = value;
|
|
398
|
+
if ("string" == typeof record.text) return record.text;
|
|
399
|
+
if (record.text && "object" == typeof record.text && "string" == typeof record.text.value) return record.text.value;
|
|
400
|
+
if ("string" == typeof record.output_text) return record.output_text;
|
|
401
|
+
if ("string" == typeof record.input_text) return record.input_text;
|
|
402
|
+
if ("string" == typeof record.value && isTextLikeContentType(record.type)) return record.value;
|
|
403
|
+
if ("content" in record) return extractTextContent(record.content, depth + 1);
|
|
382
404
|
return "";
|
|
383
405
|
}
|
|
406
|
+
function isTextLikeContentType(type) {
|
|
407
|
+
if ("string" != typeof type) return false;
|
|
408
|
+
const normalized = type.toLowerCase();
|
|
409
|
+
return "text" === normalized || "input_text" === normalized || "output_text" === normalized || "text_delta" === normalized;
|
|
410
|
+
}
|
|
384
411
|
function isToolMessage(entry) {
|
|
385
412
|
if (!entry || "object" != typeof entry) return false;
|
|
386
413
|
const role = entry.role || entry?.kwargs?.role || entry?.additional_kwargs?.role;
|
package/dist/cli/index.cjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
var __webpack_exports__ = {};
|
|
4
|
-
const external_logger_cjs_namespaceObject = require("../logger.cjs");
|
|
5
|
-
const loader_cjs_namespaceObject = require("./config/loader.cjs");
|
|
6
4
|
const env_cjs_namespaceObject = require("../gateway/env.cjs");
|
|
7
|
-
const
|
|
5
|
+
const external_logger_cjs_namespaceObject = require("../logger.cjs");
|
|
8
6
|
const agent_cjs_namespaceObject = require("./commands/agent.cjs");
|
|
9
|
-
const skill_cjs_namespaceObject = require("./commands/skill.cjs");
|
|
10
7
|
const gateway_cjs_namespaceObject = require("./commands/gateway.cjs");
|
|
11
|
-
const provider_cjs_namespaceObject = require("./commands/provider.cjs");
|
|
12
8
|
const init_cjs_namespaceObject = require("./commands/init.cjs");
|
|
9
|
+
const provider_cjs_namespaceObject = require("./commands/provider.cjs");
|
|
10
|
+
const skill_cjs_namespaceObject = require("./commands/skill.cjs");
|
|
11
|
+
const loader_cjs_namespaceObject = require("./config/loader.cjs");
|
|
12
|
+
const outputManager_cjs_namespaceObject = require("./core/outputManager.cjs");
|
|
13
13
|
function parseArgs(argv) {
|
|
14
14
|
const args = argv.slice(2);
|
|
15
15
|
if (args.includes("--help") || args.includes("-h")) return {
|
|
@@ -114,6 +114,7 @@ Examples:
|
|
|
114
114
|
wingman skill install pdf
|
|
115
115
|
wingman skill list
|
|
116
116
|
wingman provider status
|
|
117
|
+
wingman provider login codex
|
|
117
118
|
wingman provider login copilot --token="<token>"
|
|
118
119
|
wingman gateway start
|
|
119
120
|
wingman gateway join ws://localhost:3000/ws --name="agent-1"
|
package/dist/cli/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { createLogger, getLogFilePath } from "../logger.js";
|
|
3
|
-
import { WingmanConfigLoader } from "./config/loader.js";
|
|
4
2
|
import { getGatewayTokenFromEnv } from "../gateway/env.js";
|
|
5
|
-
import {
|
|
3
|
+
import { createLogger, getLogFilePath } from "../logger.js";
|
|
6
4
|
import { executeAgentCommand } from "./commands/agent.js";
|
|
7
|
-
import { executeSkillCommand } from "./commands/skill.js";
|
|
8
5
|
import { executeGatewayCommand } from "./commands/gateway.js";
|
|
9
|
-
import { executeProviderCommand } from "./commands/provider.js";
|
|
10
6
|
import { executeInitCommand } from "./commands/init.js";
|
|
7
|
+
import { executeProviderCommand } from "./commands/provider.js";
|
|
8
|
+
import { executeSkillCommand } from "./commands/skill.js";
|
|
9
|
+
import { WingmanConfigLoader } from "./config/loader.js";
|
|
10
|
+
import { OutputManager } from "./core/outputManager.js";
|
|
11
11
|
function parseArgs(argv) {
|
|
12
12
|
const args = argv.slice(2);
|
|
13
13
|
if (args.includes("--help") || args.includes("-h")) return {
|
|
@@ -112,6 +112,7 @@ Examples:
|
|
|
112
112
|
wingman skill install pdf
|
|
113
113
|
wingman skill list
|
|
114
114
|
wingman provider status
|
|
115
|
+
wingman provider login codex
|
|
115
116
|
wingman provider login copilot --token="<token>"
|
|
116
117
|
wingman gateway start
|
|
117
118
|
wingman gateway join ws://localhost:3000/ws --name="agent-1"
|
package/dist/cli/types.d.ts
CHANGED
|
@@ -3,6 +3,38 @@ export type OutputMode = "interactive" | "json";
|
|
|
3
3
|
export interface WingmanConfig {
|
|
4
4
|
logLevel?: LogLevel;
|
|
5
5
|
defaultAgent?: string;
|
|
6
|
+
summarization?: {
|
|
7
|
+
enabled?: boolean;
|
|
8
|
+
maxTokensBeforeSummary?: number;
|
|
9
|
+
messagesToKeep?: number;
|
|
10
|
+
};
|
|
11
|
+
modelRetry?: {
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
maxRetries?: number;
|
|
14
|
+
backoffFactor?: number;
|
|
15
|
+
initialDelayMs?: number;
|
|
16
|
+
maxDelayMs?: number;
|
|
17
|
+
jitter?: boolean;
|
|
18
|
+
onFailure?: "continue" | "error";
|
|
19
|
+
};
|
|
20
|
+
toolRetry?: {
|
|
21
|
+
enabled?: boolean;
|
|
22
|
+
maxRetries?: number;
|
|
23
|
+
backoffFactor?: number;
|
|
24
|
+
initialDelayMs?: number;
|
|
25
|
+
maxDelayMs?: number;
|
|
26
|
+
jitter?: boolean;
|
|
27
|
+
onFailure?: "continue" | "error";
|
|
28
|
+
tools?: string[];
|
|
29
|
+
};
|
|
30
|
+
humanInTheLoop?: {
|
|
31
|
+
enabled?: boolean;
|
|
32
|
+
interruptOn?: Record<string, boolean | {
|
|
33
|
+
allowedDecisions: Array<"approve" | "edit" | "reject">;
|
|
34
|
+
description?: string;
|
|
35
|
+
argsSchema?: Record<string, any>;
|
|
36
|
+
}>;
|
|
37
|
+
};
|
|
6
38
|
gateway?: {
|
|
7
39
|
host?: string;
|
|
8
40
|
port?: number;
|
|
@@ -63,7 +63,7 @@ const handleSessionsApi = async (ctx, req, url)=>{
|
|
|
63
63
|
const bUpdated = "number" == typeof b.updatedAt ? b.updatedAt : 0;
|
|
64
64
|
return bUpdated - aUpdated;
|
|
65
65
|
});
|
|
66
|
-
return new Response(JSON.stringify(sorted.slice(0, limit)
|
|
66
|
+
return new Response(JSON.stringify(sorted.slice(0, limit)), {
|
|
67
67
|
headers: {
|
|
68
68
|
"Content-Type": "application/json"
|
|
69
69
|
}
|
|
@@ -87,7 +87,7 @@ const handleSessionsApi = async (ctx, req, url)=>{
|
|
|
87
87
|
messageCount: session.messageCount,
|
|
88
88
|
lastMessagePreview: session.lastMessagePreview,
|
|
89
89
|
workdir: session.metadata?.workdir ?? null
|
|
90
|
-
}
|
|
90
|
+
}), {
|
|
91
91
|
headers: {
|
|
92
92
|
"Content-Type": "application/json"
|
|
93
93
|
}
|
|
@@ -107,7 +107,7 @@ const handleSessionsApi = async (ctx, req, url)=>{
|
|
|
107
107
|
const manager = await ctx.getSessionManager(agentId);
|
|
108
108
|
if ("GET" === req.method) {
|
|
109
109
|
const messages = await manager.listMessages(sessionId);
|
|
110
|
-
return new Response(JSON.stringify(messages
|
|
110
|
+
return new Response(JSON.stringify(messages), {
|
|
111
111
|
headers: {
|
|
112
112
|
"Content-Type": "application/json"
|
|
113
113
|
}
|
|
@@ -124,7 +124,7 @@ const handleSessionsApi = async (ctx, req, url)=>{
|
|
|
124
124
|
id: sessionId,
|
|
125
125
|
messageCount: updated?.messageCount ?? 0,
|
|
126
126
|
lastMessagePreview: updated?.lastMessagePreview ?? null
|
|
127
|
-
}
|
|
127
|
+
}), {
|
|
128
128
|
headers: {
|
|
129
129
|
"Content-Type": "application/json"
|
|
130
130
|
}
|
|
@@ -152,7 +152,7 @@ const handleSessionsApi = async (ctx, req, url)=>{
|
|
|
152
152
|
return new Response(JSON.stringify({
|
|
153
153
|
id: session.id,
|
|
154
154
|
workdir: null
|
|
155
|
-
}
|
|
155
|
+
}), {
|
|
156
156
|
headers: {
|
|
157
157
|
"Content-Type": "application/json"
|
|
158
158
|
}
|
|
@@ -172,7 +172,7 @@ const handleSessionsApi = async (ctx, req, url)=>{
|
|
|
172
172
|
return new Response(JSON.stringify({
|
|
173
173
|
id: session.id,
|
|
174
174
|
workdir: resolved
|
|
175
|
-
}
|
|
175
|
+
}), {
|
|
176
176
|
headers: {
|
|
177
177
|
"Content-Type": "application/json"
|
|
178
178
|
}
|
|
@@ -208,7 +208,7 @@ const handleSessionsApi = async (ctx, req, url)=>{
|
|
|
208
208
|
messageCount: updated?.messageCount ?? session.messageCount,
|
|
209
209
|
lastMessagePreview: updated?.lastMessagePreview ?? session.lastMessagePreview,
|
|
210
210
|
workdir: updated?.metadata?.workdir ?? session.metadata?.workdir ?? null
|
|
211
|
-
}
|
|
211
|
+
}), {
|
|
212
212
|
headers: {
|
|
213
213
|
"Content-Type": "application/json"
|
|
214
214
|
}
|
|
@@ -35,7 +35,7 @@ const handleSessionsApi = async (ctx, req, url)=>{
|
|
|
35
35
|
const bUpdated = "number" == typeof b.updatedAt ? b.updatedAt : 0;
|
|
36
36
|
return bUpdated - aUpdated;
|
|
37
37
|
});
|
|
38
|
-
return new Response(JSON.stringify(sorted.slice(0, limit)
|
|
38
|
+
return new Response(JSON.stringify(sorted.slice(0, limit)), {
|
|
39
39
|
headers: {
|
|
40
40
|
"Content-Type": "application/json"
|
|
41
41
|
}
|
|
@@ -59,7 +59,7 @@ const handleSessionsApi = async (ctx, req, url)=>{
|
|
|
59
59
|
messageCount: session.messageCount,
|
|
60
60
|
lastMessagePreview: session.lastMessagePreview,
|
|
61
61
|
workdir: session.metadata?.workdir ?? null
|
|
62
|
-
}
|
|
62
|
+
}), {
|
|
63
63
|
headers: {
|
|
64
64
|
"Content-Type": "application/json"
|
|
65
65
|
}
|
|
@@ -79,7 +79,7 @@ const handleSessionsApi = async (ctx, req, url)=>{
|
|
|
79
79
|
const manager = await ctx.getSessionManager(agentId);
|
|
80
80
|
if ("GET" === req.method) {
|
|
81
81
|
const messages = await manager.listMessages(sessionId);
|
|
82
|
-
return new Response(JSON.stringify(messages
|
|
82
|
+
return new Response(JSON.stringify(messages), {
|
|
83
83
|
headers: {
|
|
84
84
|
"Content-Type": "application/json"
|
|
85
85
|
}
|
|
@@ -96,7 +96,7 @@ const handleSessionsApi = async (ctx, req, url)=>{
|
|
|
96
96
|
id: sessionId,
|
|
97
97
|
messageCount: updated?.messageCount ?? 0,
|
|
98
98
|
lastMessagePreview: updated?.lastMessagePreview ?? null
|
|
99
|
-
}
|
|
99
|
+
}), {
|
|
100
100
|
headers: {
|
|
101
101
|
"Content-Type": "application/json"
|
|
102
102
|
}
|
|
@@ -124,7 +124,7 @@ const handleSessionsApi = async (ctx, req, url)=>{
|
|
|
124
124
|
return new Response(JSON.stringify({
|
|
125
125
|
id: session.id,
|
|
126
126
|
workdir: null
|
|
127
|
-
}
|
|
127
|
+
}), {
|
|
128
128
|
headers: {
|
|
129
129
|
"Content-Type": "application/json"
|
|
130
130
|
}
|
|
@@ -144,7 +144,7 @@ const handleSessionsApi = async (ctx, req, url)=>{
|
|
|
144
144
|
return new Response(JSON.stringify({
|
|
145
145
|
id: session.id,
|
|
146
146
|
workdir: resolved
|
|
147
|
-
}
|
|
147
|
+
}), {
|
|
148
148
|
headers: {
|
|
149
149
|
"Content-Type": "application/json"
|
|
150
150
|
}
|
|
@@ -180,7 +180,7 @@ const handleSessionsApi = async (ctx, req, url)=>{
|
|
|
180
180
|
messageCount: updated?.messageCount ?? session.messageCount,
|
|
181
181
|
lastMessagePreview: updated?.lastMessagePreview ?? session.lastMessagePreview,
|
|
182
182
|
workdir: updated?.metadata?.workdir ?? session.metadata?.workdir ?? null
|
|
183
|
-
}
|
|
183
|
+
}), {
|
|
184
184
|
headers: {
|
|
185
185
|
"Content-Type": "application/json"
|
|
186
186
|
}
|