@wingman-ai/gateway 0.1.5 → 0.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/.wingman/agents/README.md +7 -0
- package/.wingman/agents/coding/agent.md +1 -0
- package/.wingman/agents/main/agent.md +1 -0
- package/.wingman/agents/researcher/agent.md +1 -0
- package/.wingman/agents/stock-trader/agent.md +1 -0
- package/dist/agent/config/agentConfig.cjs +12 -1
- package/dist/agent/config/agentConfig.d.ts +14 -0
- package/dist/agent/config/agentConfig.js +12 -1
- package/dist/agent/config/agentLoader.cjs +37 -1
- package/dist/agent/config/agentLoader.d.ts +2 -1
- package/dist/agent/config/agentLoader.js +37 -1
- package/dist/agent/config/modelFactory.cjs +2 -1
- package/dist/agent/config/modelFactory.js +2 -1
- package/dist/agent/config/toolRegistry.cjs +6 -4
- package/dist/agent/config/toolRegistry.d.ts +1 -0
- package/dist/agent/config/toolRegistry.js +6 -4
- package/dist/agent/middleware/additional-messages.cjs +8 -1
- package/dist/agent/middleware/additional-messages.d.ts +1 -0
- package/dist/agent/middleware/additional-messages.js +8 -1
- package/dist/agent/tests/agentConfig.test.cjs +25 -0
- package/dist/agent/tests/agentConfig.test.js +25 -0
- package/dist/agent/tests/agentLoader.test.cjs +18 -0
- package/dist/agent/tests/agentLoader.test.js +18 -0
- package/dist/agent/tests/modelFactory.test.cjs +13 -0
- package/dist/agent/tests/modelFactory.test.js +14 -1
- package/dist/agent/tests/toolRegistry.test.cjs +15 -0
- package/dist/agent/tests/toolRegistry.test.js +15 -0
- package/dist/agent/tools/code_search.cjs +1 -1
- package/dist/agent/tools/code_search.js +1 -1
- package/dist/agent/tools/command_execute.cjs +1 -1
- package/dist/agent/tools/command_execute.js +1 -1
- package/dist/agent/tools/ui_registry.d.ts +3 -3
- package/dist/cli/core/agentInvoker.cjs +212 -21
- package/dist/cli/core/agentInvoker.d.ts +55 -20
- package/dist/cli/core/agentInvoker.js +197 -21
- package/dist/cli/core/sessionManager.cjs +93 -4
- package/dist/cli/core/sessionManager.d.ts +1 -1
- package/dist/cli/core/sessionManager.js +93 -4
- package/dist/gateway/http/agents.cjs +121 -10
- package/dist/gateway/http/agents.js +121 -10
- package/dist/gateway/index.cjs +2 -2
- package/dist/gateway/server.cjs +55 -17
- package/dist/gateway/server.js +55 -17
- package/dist/gateway/types.d.ts +9 -1
- package/dist/tests/additionalMessageMiddleware.test.cjs +26 -0
- package/dist/tests/additionalMessageMiddleware.test.js +26 -0
- package/dist/tests/agentInvokerAttachments.test.cjs +123 -0
- package/dist/tests/agentInvokerAttachments.test.js +123 -0
- package/dist/tests/agentInvokerWorkdir.test.cjs +100 -0
- package/dist/tests/agentInvokerWorkdir.test.d.ts +1 -0
- package/dist/tests/agentInvokerWorkdir.test.js +72 -0
- package/dist/tests/agents-api.test.cjs +232 -0
- package/dist/tests/agents-api.test.d.ts +1 -0
- package/dist/tests/agents-api.test.js +226 -0
- package/dist/tests/gateway.test.cjs +21 -0
- package/dist/tests/gateway.test.js +21 -0
- package/dist/tests/sessionMessageAttachments.test.cjs +59 -0
- package/dist/tests/sessionMessageAttachments.test.js +59 -0
- package/dist/types/agents.d.ts +5 -0
- package/dist/webui/assets/index-BytPznA_.css +1 -0
- package/dist/webui/assets/index-u_5qlVip.js +176 -0
- package/dist/webui/index.html +2 -2
- package/package.json +3 -3
- package/.wingman/agents/wingman/agent.json +0 -12
- package/dist/webui/assets/index-CyE7T5pV.js +0 -162
- package/dist/webui/assets/index-DMEHdune.css +0 -1
|
@@ -33,8 +33,79 @@ const external_node_fs_namespaceObject = require("node:fs");
|
|
|
33
33
|
const external_node_path_namespaceObject = require("node:path");
|
|
34
34
|
const external_js_yaml_namespaceObject = require("js-yaml");
|
|
35
35
|
const voice_cjs_namespaceObject = require("../../types/voice.cjs");
|
|
36
|
+
const hasOwn = (value, key)=>Boolean(value && Object.prototype.hasOwnProperty.call(value, key));
|
|
37
|
+
const getPromptTrainingFromPayload = (payload)=>{
|
|
38
|
+
if (hasOwn(payload, "promptTraining")) return payload.promptTraining;
|
|
39
|
+
if (hasOwn(payload, "promptRefinement")) return payload.promptRefinement;
|
|
40
|
+
};
|
|
41
|
+
const mapPromptTrainingFields = (value)=>({
|
|
42
|
+
promptTraining: value,
|
|
43
|
+
promptRefinement: value
|
|
44
|
+
});
|
|
45
|
+
const mapSubAgentForResponse = (sub)=>({
|
|
46
|
+
id: sub.name,
|
|
47
|
+
displayName: sub.name,
|
|
48
|
+
description: sub.description,
|
|
49
|
+
tools: sub.tools || [],
|
|
50
|
+
model: sub.model,
|
|
51
|
+
prompt: sub.systemPrompt,
|
|
52
|
+
...mapPromptTrainingFields(sub.promptRefinement)
|
|
53
|
+
});
|
|
54
|
+
const normalizeSubAgents = (rawSubAgents)=>{
|
|
55
|
+
if (null == rawSubAgents) return {
|
|
56
|
+
ok: true,
|
|
57
|
+
value: []
|
|
58
|
+
};
|
|
59
|
+
if (!Array.isArray(rawSubAgents)) return {
|
|
60
|
+
ok: false,
|
|
61
|
+
error: "Invalid subAgents: expected an array"
|
|
62
|
+
};
|
|
63
|
+
const availableTools = (0, toolRegistry_cjs_namespaceObject.getAvailableTools)();
|
|
64
|
+
const normalized = [];
|
|
65
|
+
for(let index = 0; index < rawSubAgents.length; index += 1){
|
|
66
|
+
const item = rawSubAgents[index];
|
|
67
|
+
if (!item || "object" != typeof item) return {
|
|
68
|
+
ok: false,
|
|
69
|
+
error: `Invalid subAgents[${index}]: expected an object`
|
|
70
|
+
};
|
|
71
|
+
const name = (item.id || item.name || "").trim();
|
|
72
|
+
if (!name || !/^[a-zA-Z0-9_-]+$/.test(name)) return {
|
|
73
|
+
ok: false,
|
|
74
|
+
error: `Invalid subAgents[${index}].id`
|
|
75
|
+
};
|
|
76
|
+
const prompt = (item.prompt ?? item.systemPrompt ?? "").trim();
|
|
77
|
+
if (!prompt) return {
|
|
78
|
+
ok: false,
|
|
79
|
+
error: `Invalid subAgents[${index}].prompt`
|
|
80
|
+
};
|
|
81
|
+
const description = (item.description || "").trim();
|
|
82
|
+
if (!description) return {
|
|
83
|
+
ok: false,
|
|
84
|
+
error: `Invalid subAgents[${index}].description`
|
|
85
|
+
};
|
|
86
|
+
const promptTraining = getPromptTrainingFromPayload(item);
|
|
87
|
+
if (null != promptTraining && "boolean" != typeof promptTraining && ("object" != typeof promptTraining || Array.isArray(promptTraining))) return {
|
|
88
|
+
ok: false,
|
|
89
|
+
error: `Invalid subAgents[${index}].promptTraining`
|
|
90
|
+
};
|
|
91
|
+
const tools = Array.isArray(item.tools) ? item.tools.filter((tool)=>availableTools.includes(tool)) : [];
|
|
92
|
+
const sub = {
|
|
93
|
+
name,
|
|
94
|
+
description,
|
|
95
|
+
tools,
|
|
96
|
+
model: item.model?.trim() || void 0,
|
|
97
|
+
systemPrompt: prompt
|
|
98
|
+
};
|
|
99
|
+
if (null != promptTraining) sub.promptRefinement = promptTraining;
|
|
100
|
+
normalized.push(sub);
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
ok: true,
|
|
104
|
+
value: normalized
|
|
105
|
+
};
|
|
106
|
+
};
|
|
36
107
|
const buildAgentMarkdown = (params)=>{
|
|
37
|
-
const { id, description, tools, model, prompt, voice } = params;
|
|
108
|
+
const { id, description, tools, model, prompt, voice, promptRefinement, subAgents } = params;
|
|
38
109
|
const metadata = {
|
|
39
110
|
name: id,
|
|
40
111
|
description: description || "New Wingman agent",
|
|
@@ -42,6 +113,8 @@ const buildAgentMarkdown = (params)=>{
|
|
|
42
113
|
};
|
|
43
114
|
if (model) metadata.model = model;
|
|
44
115
|
if (voice) metadata.voice = voice;
|
|
116
|
+
if (void 0 !== promptRefinement) metadata.promptRefinement = promptRefinement;
|
|
117
|
+
if (subAgents && subAgents.length > 0) metadata.subAgents = subAgents;
|
|
45
118
|
return serializeAgentMarkdown(metadata, prompt || "You are a Wingman agent.");
|
|
46
119
|
};
|
|
47
120
|
const parseAgentMarkdown = (content)=>{
|
|
@@ -79,13 +152,8 @@ const handleAgentsApi = async (ctx, req, url)=>{
|
|
|
79
152
|
tools: agent.tools || [],
|
|
80
153
|
model: agent.model,
|
|
81
154
|
voice: agent.voice,
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
displayName: sub.name,
|
|
85
|
-
description: sub.description,
|
|
86
|
-
tools: sub.tools || [],
|
|
87
|
-
model: sub.model
|
|
88
|
-
})) || []
|
|
155
|
+
...mapPromptTrainingFields(agent.promptRefinement),
|
|
156
|
+
subAgents: agent.subAgents?.map((sub)=>mapSubAgentForResponse(sub)) || []
|
|
89
157
|
}));
|
|
90
158
|
return new Response(JSON.stringify({
|
|
91
159
|
agents,
|
|
@@ -112,6 +180,15 @@ const handleAgentsApi = async (ctx, req, url)=>{
|
|
|
112
180
|
status: 400
|
|
113
181
|
});
|
|
114
182
|
const tools = Array.isArray(body.tools) ? body.tools.filter((tool)=>(0, toolRegistry_cjs_namespaceObject.getAvailableTools)().includes(tool)) : [];
|
|
183
|
+
const promptTraining = getPromptTrainingFromPayload(body);
|
|
184
|
+
if (null != promptTraining && "boolean" != typeof promptTraining && ("object" != typeof promptTraining || Array.isArray(promptTraining))) return new Response("Invalid promptTraining configuration", {
|
|
185
|
+
status: 400
|
|
186
|
+
});
|
|
187
|
+
const rawSubAgents = hasOwn(body, "subAgents") ? body.subAgents : body.subagents;
|
|
188
|
+
const subAgentsResult = normalizeSubAgents(rawSubAgents);
|
|
189
|
+
if (!subAgentsResult.ok) return new Response(subAgentsResult.error, {
|
|
190
|
+
status: 400
|
|
191
|
+
});
|
|
115
192
|
const agentsDir = (0, external_node_path_namespaceObject.join)(ctx.resolveConfigDirPath(), "agents", id);
|
|
116
193
|
if ((0, external_node_fs_namespaceObject.existsSync)(agentsDir)) return new Response("Agent already exists", {
|
|
117
194
|
status: 409
|
|
@@ -125,7 +202,9 @@ const handleAgentsApi = async (ctx, req, url)=>{
|
|
|
125
202
|
tools,
|
|
126
203
|
model: body.model,
|
|
127
204
|
prompt: body.prompt,
|
|
128
|
-
voice: parsedVoice
|
|
205
|
+
voice: parsedVoice,
|
|
206
|
+
promptRefinement: null === promptTraining ? void 0 : promptTraining,
|
|
207
|
+
subAgents: subAgentsResult.value
|
|
129
208
|
});
|
|
130
209
|
(0, external_node_fs_namespaceObject.writeFileSync)((0, external_node_path_namespaceObject.join)(agentsDir, "agent.md"), agentMarkdown);
|
|
131
210
|
const agentList = config.agents?.list || [];
|
|
@@ -149,7 +228,9 @@ const handleAgentsApi = async (ctx, req, url)=>{
|
|
|
149
228
|
description: body.description,
|
|
150
229
|
tools,
|
|
151
230
|
model: body.model,
|
|
152
|
-
voice: parsedVoice
|
|
231
|
+
voice: parsedVoice,
|
|
232
|
+
...mapPromptTrainingFields(null === promptTraining ? void 0 : promptTraining),
|
|
233
|
+
subAgents: subAgentsResult.value.map((sub)=>mapSubAgentForResponse(sub))
|
|
153
234
|
}, null, 2), {
|
|
154
235
|
headers: {
|
|
155
236
|
"Content-Type": "application/json"
|
|
@@ -178,6 +259,8 @@ const handleAgentsApi = async (ctx, req, url)=>{
|
|
|
178
259
|
tools: agentConfig.tools || [],
|
|
179
260
|
model: agentConfig.model,
|
|
180
261
|
voice: agentConfig.voice,
|
|
262
|
+
...mapPromptTrainingFields(agentConfig.promptRefinement),
|
|
263
|
+
subAgents: agentConfig.subAgents?.map((sub)=>mapSubAgentForResponse(sub)) || [],
|
|
181
264
|
prompt: agentConfig.systemPrompt
|
|
182
265
|
}, null, 2), {
|
|
183
266
|
headers: {
|
|
@@ -204,6 +287,18 @@ const handleAgentsApi = async (ctx, req, url)=>{
|
|
|
204
287
|
const nextModel = body.model ?? agentConfig.model;
|
|
205
288
|
const nextPrompt = body.prompt ?? agentConfig.systemPrompt;
|
|
206
289
|
const nextVoice = void 0 === parsedVoice ? agentConfig.voice : parsedVoice;
|
|
290
|
+
const bodyPromptTraining = getPromptTrainingFromPayload(body);
|
|
291
|
+
if (null != bodyPromptTraining && "boolean" != typeof bodyPromptTraining && ("object" != typeof bodyPromptTraining || Array.isArray(bodyPromptTraining))) return new Response("Invalid promptTraining configuration", {
|
|
292
|
+
status: 400
|
|
293
|
+
});
|
|
294
|
+
const nextPromptRefinement = void 0 === bodyPromptTraining ? agentConfig.promptRefinement : null === bodyPromptTraining ? void 0 : bodyPromptTraining;
|
|
295
|
+
const hasSubAgents = hasOwn(body, "subAgents") || hasOwn(body, "subagents");
|
|
296
|
+
const rawSubAgents = hasOwn(body, "subAgents") ? body.subAgents : body.subagents;
|
|
297
|
+
const subAgentsResult = normalizeSubAgents(rawSubAgents);
|
|
298
|
+
if (!subAgentsResult.ok) return new Response(subAgentsResult.error, {
|
|
299
|
+
status: 400
|
|
300
|
+
});
|
|
301
|
+
const nextSubAgents = hasSubAgents ? subAgentsResult.value : agentConfig.subAgents || [];
|
|
207
302
|
const agentsDir = (0, external_node_path_namespaceObject.join)(ctx.resolveConfigDirPath(), "agents", agentId);
|
|
208
303
|
const agentJsonPath = (0, external_node_path_namespaceObject.join)(agentsDir, "agent.json");
|
|
209
304
|
const agentMarkdownPath = (0, external_node_path_namespaceObject.join)(agentsDir, "agent.md");
|
|
@@ -223,6 +318,13 @@ const handleAgentsApi = async (ctx, req, url)=>{
|
|
|
223
318
|
parsed.systemPrompt = nextPrompt;
|
|
224
319
|
if (nextVoice) parsed.voice = nextVoice;
|
|
225
320
|
else delete parsed.voice;
|
|
321
|
+
if (void 0 !== nextPromptRefinement) parsed.promptRefinement = nextPromptRefinement;
|
|
322
|
+
else delete parsed.promptRefinement;
|
|
323
|
+
if (nextSubAgents.length > 0) parsed.subAgents = nextSubAgents;
|
|
324
|
+
else {
|
|
325
|
+
delete parsed.subAgents;
|
|
326
|
+
delete parsed.subagents;
|
|
327
|
+
}
|
|
226
328
|
(0, external_node_fs_namespaceObject.writeFileSync)(agentJsonPath, JSON.stringify(parsed, null, 2));
|
|
227
329
|
} else if (hasMarkdown) {
|
|
228
330
|
const raw = (0, external_node_fs_namespaceObject.readFileSync)(agentMarkdownPath, "utf-8");
|
|
@@ -234,6 +336,13 @@ const handleAgentsApi = async (ctx, req, url)=>{
|
|
|
234
336
|
else delete metadata.model;
|
|
235
337
|
if (nextVoice) metadata.voice = nextVoice;
|
|
236
338
|
else delete metadata.voice;
|
|
339
|
+
if (void 0 !== nextPromptRefinement) metadata.promptRefinement = nextPromptRefinement;
|
|
340
|
+
else delete metadata.promptRefinement;
|
|
341
|
+
if (nextSubAgents.length > 0) metadata.subAgents = nextSubAgents;
|
|
342
|
+
else {
|
|
343
|
+
delete metadata.subAgents;
|
|
344
|
+
delete metadata.subagents;
|
|
345
|
+
}
|
|
237
346
|
const updatedMarkdown = serializeAgentMarkdown(metadata, nextPrompt);
|
|
238
347
|
(0, external_node_fs_namespaceObject.writeFileSync)(agentMarkdownPath, updatedMarkdown);
|
|
239
348
|
}
|
|
@@ -260,6 +369,8 @@ const handleAgentsApi = async (ctx, req, url)=>{
|
|
|
260
369
|
tools,
|
|
261
370
|
model: nextModel,
|
|
262
371
|
voice: nextVoice,
|
|
372
|
+
...mapPromptTrainingFields(nextPromptRefinement),
|
|
373
|
+
subAgents: nextSubAgents.map((sub)=>mapSubAgentForResponse(sub)),
|
|
263
374
|
prompt: nextPrompt
|
|
264
375
|
}, null, 2), {
|
|
265
376
|
headers: {
|
|
@@ -5,8 +5,79 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { dump, load } from "js-yaml";
|
|
7
7
|
import { AgentVoiceConfigSchema } from "../../types/voice.js";
|
|
8
|
+
const hasOwn = (value, key)=>Boolean(value && Object.prototype.hasOwnProperty.call(value, key));
|
|
9
|
+
const getPromptTrainingFromPayload = (payload)=>{
|
|
10
|
+
if (hasOwn(payload, "promptTraining")) return payload.promptTraining;
|
|
11
|
+
if (hasOwn(payload, "promptRefinement")) return payload.promptRefinement;
|
|
12
|
+
};
|
|
13
|
+
const mapPromptTrainingFields = (value)=>({
|
|
14
|
+
promptTraining: value,
|
|
15
|
+
promptRefinement: value
|
|
16
|
+
});
|
|
17
|
+
const mapSubAgentForResponse = (sub)=>({
|
|
18
|
+
id: sub.name,
|
|
19
|
+
displayName: sub.name,
|
|
20
|
+
description: sub.description,
|
|
21
|
+
tools: sub.tools || [],
|
|
22
|
+
model: sub.model,
|
|
23
|
+
prompt: sub.systemPrompt,
|
|
24
|
+
...mapPromptTrainingFields(sub.promptRefinement)
|
|
25
|
+
});
|
|
26
|
+
const normalizeSubAgents = (rawSubAgents)=>{
|
|
27
|
+
if (null == rawSubAgents) return {
|
|
28
|
+
ok: true,
|
|
29
|
+
value: []
|
|
30
|
+
};
|
|
31
|
+
if (!Array.isArray(rawSubAgents)) return {
|
|
32
|
+
ok: false,
|
|
33
|
+
error: "Invalid subAgents: expected an array"
|
|
34
|
+
};
|
|
35
|
+
const availableTools = getAvailableTools();
|
|
36
|
+
const normalized = [];
|
|
37
|
+
for(let index = 0; index < rawSubAgents.length; index += 1){
|
|
38
|
+
const item = rawSubAgents[index];
|
|
39
|
+
if (!item || "object" != typeof item) return {
|
|
40
|
+
ok: false,
|
|
41
|
+
error: `Invalid subAgents[${index}]: expected an object`
|
|
42
|
+
};
|
|
43
|
+
const name = (item.id || item.name || "").trim();
|
|
44
|
+
if (!name || !/^[a-zA-Z0-9_-]+$/.test(name)) return {
|
|
45
|
+
ok: false,
|
|
46
|
+
error: `Invalid subAgents[${index}].id`
|
|
47
|
+
};
|
|
48
|
+
const prompt = (item.prompt ?? item.systemPrompt ?? "").trim();
|
|
49
|
+
if (!prompt) return {
|
|
50
|
+
ok: false,
|
|
51
|
+
error: `Invalid subAgents[${index}].prompt`
|
|
52
|
+
};
|
|
53
|
+
const description = (item.description || "").trim();
|
|
54
|
+
if (!description) return {
|
|
55
|
+
ok: false,
|
|
56
|
+
error: `Invalid subAgents[${index}].description`
|
|
57
|
+
};
|
|
58
|
+
const promptTraining = getPromptTrainingFromPayload(item);
|
|
59
|
+
if (null != promptTraining && "boolean" != typeof promptTraining && ("object" != typeof promptTraining || Array.isArray(promptTraining))) return {
|
|
60
|
+
ok: false,
|
|
61
|
+
error: `Invalid subAgents[${index}].promptTraining`
|
|
62
|
+
};
|
|
63
|
+
const tools = Array.isArray(item.tools) ? item.tools.filter((tool)=>availableTools.includes(tool)) : [];
|
|
64
|
+
const sub = {
|
|
65
|
+
name,
|
|
66
|
+
description,
|
|
67
|
+
tools,
|
|
68
|
+
model: item.model?.trim() || void 0,
|
|
69
|
+
systemPrompt: prompt
|
|
70
|
+
};
|
|
71
|
+
if (null != promptTraining) sub.promptRefinement = promptTraining;
|
|
72
|
+
normalized.push(sub);
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
ok: true,
|
|
76
|
+
value: normalized
|
|
77
|
+
};
|
|
78
|
+
};
|
|
8
79
|
const buildAgentMarkdown = (params)=>{
|
|
9
|
-
const { id, description, tools, model, prompt, voice } = params;
|
|
80
|
+
const { id, description, tools, model, prompt, voice, promptRefinement, subAgents } = params;
|
|
10
81
|
const metadata = {
|
|
11
82
|
name: id,
|
|
12
83
|
description: description || "New Wingman agent",
|
|
@@ -14,6 +85,8 @@ const buildAgentMarkdown = (params)=>{
|
|
|
14
85
|
};
|
|
15
86
|
if (model) metadata.model = model;
|
|
16
87
|
if (voice) metadata.voice = voice;
|
|
88
|
+
if (void 0 !== promptRefinement) metadata.promptRefinement = promptRefinement;
|
|
89
|
+
if (subAgents && subAgents.length > 0) metadata.subAgents = subAgents;
|
|
17
90
|
return serializeAgentMarkdown(metadata, prompt || "You are a Wingman agent.");
|
|
18
91
|
};
|
|
19
92
|
const parseAgentMarkdown = (content)=>{
|
|
@@ -51,13 +124,8 @@ const handleAgentsApi = async (ctx, req, url)=>{
|
|
|
51
124
|
tools: agent.tools || [],
|
|
52
125
|
model: agent.model,
|
|
53
126
|
voice: agent.voice,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
displayName: sub.name,
|
|
57
|
-
description: sub.description,
|
|
58
|
-
tools: sub.tools || [],
|
|
59
|
-
model: sub.model
|
|
60
|
-
})) || []
|
|
127
|
+
...mapPromptTrainingFields(agent.promptRefinement),
|
|
128
|
+
subAgents: agent.subAgents?.map((sub)=>mapSubAgentForResponse(sub)) || []
|
|
61
129
|
}));
|
|
62
130
|
return new Response(JSON.stringify({
|
|
63
131
|
agents,
|
|
@@ -84,6 +152,15 @@ const handleAgentsApi = async (ctx, req, url)=>{
|
|
|
84
152
|
status: 400
|
|
85
153
|
});
|
|
86
154
|
const tools = Array.isArray(body.tools) ? body.tools.filter((tool)=>getAvailableTools().includes(tool)) : [];
|
|
155
|
+
const promptTraining = getPromptTrainingFromPayload(body);
|
|
156
|
+
if (null != promptTraining && "boolean" != typeof promptTraining && ("object" != typeof promptTraining || Array.isArray(promptTraining))) return new Response("Invalid promptTraining configuration", {
|
|
157
|
+
status: 400
|
|
158
|
+
});
|
|
159
|
+
const rawSubAgents = hasOwn(body, "subAgents") ? body.subAgents : body.subagents;
|
|
160
|
+
const subAgentsResult = normalizeSubAgents(rawSubAgents);
|
|
161
|
+
if (!subAgentsResult.ok) return new Response(subAgentsResult.error, {
|
|
162
|
+
status: 400
|
|
163
|
+
});
|
|
87
164
|
const agentsDir = join(ctx.resolveConfigDirPath(), "agents", id);
|
|
88
165
|
if (existsSync(agentsDir)) return new Response("Agent already exists", {
|
|
89
166
|
status: 409
|
|
@@ -97,7 +174,9 @@ const handleAgentsApi = async (ctx, req, url)=>{
|
|
|
97
174
|
tools,
|
|
98
175
|
model: body.model,
|
|
99
176
|
prompt: body.prompt,
|
|
100
|
-
voice: parsedVoice
|
|
177
|
+
voice: parsedVoice,
|
|
178
|
+
promptRefinement: null === promptTraining ? void 0 : promptTraining,
|
|
179
|
+
subAgents: subAgentsResult.value
|
|
101
180
|
});
|
|
102
181
|
writeFileSync(join(agentsDir, "agent.md"), agentMarkdown);
|
|
103
182
|
const agentList = config.agents?.list || [];
|
|
@@ -121,7 +200,9 @@ const handleAgentsApi = async (ctx, req, url)=>{
|
|
|
121
200
|
description: body.description,
|
|
122
201
|
tools,
|
|
123
202
|
model: body.model,
|
|
124
|
-
voice: parsedVoice
|
|
203
|
+
voice: parsedVoice,
|
|
204
|
+
...mapPromptTrainingFields(null === promptTraining ? void 0 : promptTraining),
|
|
205
|
+
subAgents: subAgentsResult.value.map((sub)=>mapSubAgentForResponse(sub))
|
|
125
206
|
}, null, 2), {
|
|
126
207
|
headers: {
|
|
127
208
|
"Content-Type": "application/json"
|
|
@@ -150,6 +231,8 @@ const handleAgentsApi = async (ctx, req, url)=>{
|
|
|
150
231
|
tools: agentConfig.tools || [],
|
|
151
232
|
model: agentConfig.model,
|
|
152
233
|
voice: agentConfig.voice,
|
|
234
|
+
...mapPromptTrainingFields(agentConfig.promptRefinement),
|
|
235
|
+
subAgents: agentConfig.subAgents?.map((sub)=>mapSubAgentForResponse(sub)) || [],
|
|
153
236
|
prompt: agentConfig.systemPrompt
|
|
154
237
|
}, null, 2), {
|
|
155
238
|
headers: {
|
|
@@ -176,6 +259,18 @@ const handleAgentsApi = async (ctx, req, url)=>{
|
|
|
176
259
|
const nextModel = body.model ?? agentConfig.model;
|
|
177
260
|
const nextPrompt = body.prompt ?? agentConfig.systemPrompt;
|
|
178
261
|
const nextVoice = void 0 === parsedVoice ? agentConfig.voice : parsedVoice;
|
|
262
|
+
const bodyPromptTraining = getPromptTrainingFromPayload(body);
|
|
263
|
+
if (null != bodyPromptTraining && "boolean" != typeof bodyPromptTraining && ("object" != typeof bodyPromptTraining || Array.isArray(bodyPromptTraining))) return new Response("Invalid promptTraining configuration", {
|
|
264
|
+
status: 400
|
|
265
|
+
});
|
|
266
|
+
const nextPromptRefinement = void 0 === bodyPromptTraining ? agentConfig.promptRefinement : null === bodyPromptTraining ? void 0 : bodyPromptTraining;
|
|
267
|
+
const hasSubAgents = hasOwn(body, "subAgents") || hasOwn(body, "subagents");
|
|
268
|
+
const rawSubAgents = hasOwn(body, "subAgents") ? body.subAgents : body.subagents;
|
|
269
|
+
const subAgentsResult = normalizeSubAgents(rawSubAgents);
|
|
270
|
+
if (!subAgentsResult.ok) return new Response(subAgentsResult.error, {
|
|
271
|
+
status: 400
|
|
272
|
+
});
|
|
273
|
+
const nextSubAgents = hasSubAgents ? subAgentsResult.value : agentConfig.subAgents || [];
|
|
179
274
|
const agentsDir = join(ctx.resolveConfigDirPath(), "agents", agentId);
|
|
180
275
|
const agentJsonPath = join(agentsDir, "agent.json");
|
|
181
276
|
const agentMarkdownPath = join(agentsDir, "agent.md");
|
|
@@ -195,6 +290,13 @@ const handleAgentsApi = async (ctx, req, url)=>{
|
|
|
195
290
|
parsed.systemPrompt = nextPrompt;
|
|
196
291
|
if (nextVoice) parsed.voice = nextVoice;
|
|
197
292
|
else delete parsed.voice;
|
|
293
|
+
if (void 0 !== nextPromptRefinement) parsed.promptRefinement = nextPromptRefinement;
|
|
294
|
+
else delete parsed.promptRefinement;
|
|
295
|
+
if (nextSubAgents.length > 0) parsed.subAgents = nextSubAgents;
|
|
296
|
+
else {
|
|
297
|
+
delete parsed.subAgents;
|
|
298
|
+
delete parsed.subagents;
|
|
299
|
+
}
|
|
198
300
|
writeFileSync(agentJsonPath, JSON.stringify(parsed, null, 2));
|
|
199
301
|
} else if (hasMarkdown) {
|
|
200
302
|
const raw = readFileSync(agentMarkdownPath, "utf-8");
|
|
@@ -206,6 +308,13 @@ const handleAgentsApi = async (ctx, req, url)=>{
|
|
|
206
308
|
else delete metadata.model;
|
|
207
309
|
if (nextVoice) metadata.voice = nextVoice;
|
|
208
310
|
else delete metadata.voice;
|
|
311
|
+
if (void 0 !== nextPromptRefinement) metadata.promptRefinement = nextPromptRefinement;
|
|
312
|
+
else delete metadata.promptRefinement;
|
|
313
|
+
if (nextSubAgents.length > 0) metadata.subAgents = nextSubAgents;
|
|
314
|
+
else {
|
|
315
|
+
delete metadata.subAgents;
|
|
316
|
+
delete metadata.subagents;
|
|
317
|
+
}
|
|
209
318
|
const updatedMarkdown = serializeAgentMarkdown(metadata, nextPrompt);
|
|
210
319
|
writeFileSync(agentMarkdownPath, updatedMarkdown);
|
|
211
320
|
}
|
|
@@ -232,6 +341,8 @@ const handleAgentsApi = async (ctx, req, url)=>{
|
|
|
232
341
|
tools,
|
|
233
342
|
model: nextModel,
|
|
234
343
|
voice: nextVoice,
|
|
344
|
+
...mapPromptTrainingFields(nextPromptRefinement),
|
|
345
|
+
subAgents: nextSubAgents.map((sub)=>mapSubAgentForResponse(sub)),
|
|
235
346
|
prompt: nextPrompt
|
|
236
347
|
}, null, 2), {
|
|
237
348
|
headers: {
|
package/dist/gateway/index.cjs
CHANGED
|
@@ -91,9 +91,9 @@ var __webpack_exports__ = {};
|
|
|
91
91
|
"GatewayDaemon",
|
|
92
92
|
"default",
|
|
93
93
|
"NodeManager",
|
|
94
|
-
"GatewayRpcClient",
|
|
95
|
-
"BroadcastGroupManager",
|
|
96
94
|
"GatewayAuth",
|
|
95
|
+
"BroadcastGroupManager",
|
|
96
|
+
"GatewayRpcClient",
|
|
97
97
|
"GatewayServer"
|
|
98
98
|
].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] = ()=>_types_js__rspack_import_7[__rspack_import_key];
|
|
99
99
|
__webpack_require__.d(__webpack_exports__, __rspack_reexport);
|
package/dist/gateway/server.cjs
CHANGED
|
@@ -64,6 +64,21 @@ function _define_property(obj, key, value) {
|
|
|
64
64
|
else obj[key] = value;
|
|
65
65
|
return obj;
|
|
66
66
|
}
|
|
67
|
+
const API_CORS_HEADERS = {
|
|
68
|
+
"Access-Control-Allow-Origin": "*",
|
|
69
|
+
"Access-Control-Allow-Methods": "GET,POST,PUT,DELETE,OPTIONS",
|
|
70
|
+
"Access-Control-Allow-Headers": "Content-Type, Authorization, X-Wingman-Token, X-Wingman-Password",
|
|
71
|
+
"Access-Control-Max-Age": "600"
|
|
72
|
+
};
|
|
73
|
+
function withApiCors(response) {
|
|
74
|
+
const headers = new Headers(response.headers);
|
|
75
|
+
for (const [key, value] of Object.entries(API_CORS_HEADERS))headers.set(key, value);
|
|
76
|
+
return new Response(response.body, {
|
|
77
|
+
status: response.status,
|
|
78
|
+
statusText: response.statusText,
|
|
79
|
+
headers
|
|
80
|
+
});
|
|
81
|
+
}
|
|
67
82
|
class GatewayServer {
|
|
68
83
|
async start() {
|
|
69
84
|
if (void 0 === globalThis.Bun) throw new Error("Gateway server requires Bun runtime. Start with `bun ./bin/wingman gateway start`.");
|
|
@@ -381,7 +396,10 @@ class GatewayServer {
|
|
|
381
396
|
this.broadcastSessionEvent(sessionKey, sessionMessage, ws);
|
|
382
397
|
this.broadcastToClients(sessionMessage, {
|
|
383
398
|
exclude: ws,
|
|
384
|
-
|
|
399
|
+
clientTypes: [
|
|
400
|
+
"webui",
|
|
401
|
+
"desktop"
|
|
402
|
+
],
|
|
385
403
|
skipSessionId: sessionKey
|
|
386
404
|
});
|
|
387
405
|
const outputManager = new outputManager_cjs_namespaceObject.OutputManager("interactive");
|
|
@@ -621,14 +639,18 @@ class GatewayServer {
|
|
|
621
639
|
}
|
|
622
640
|
broadcastToClients(message, options) {
|
|
623
641
|
let sent = 0;
|
|
624
|
-
for (const ws of this.connectedClients)
|
|
625
|
-
if (!options?.
|
|
626
|
-
if (options?.
|
|
627
|
-
|
|
628
|
-
|
|
642
|
+
for (const ws of this.connectedClients){
|
|
643
|
+
if (!options?.exclude || ws !== options.exclude) {
|
|
644
|
+
if (!options?.clientType || ws.data.clientType === options.clientType) {
|
|
645
|
+
if (!options?.clientTypes || !(options.clientTypes.length > 0) || options.clientTypes.includes(ws.data.clientType || "")) {
|
|
646
|
+
if (options?.skipSessionId) {
|
|
647
|
+
const subscribers = this.sessionSubscriptions.get(options.skipSessionId);
|
|
648
|
+
if (subscribers?.has(ws)) continue;
|
|
649
|
+
}
|
|
650
|
+
this.sendMessage(ws, message);
|
|
651
|
+
sent++;
|
|
652
|
+
}
|
|
629
653
|
}
|
|
630
|
-
this.sendMessage(ws, message);
|
|
631
|
-
sent++;
|
|
632
654
|
}
|
|
633
655
|
}
|
|
634
656
|
return sent;
|
|
@@ -877,6 +899,9 @@ class GatewayServer {
|
|
|
877
899
|
const webhookResponse = await (0, webhooks_cjs_namespaceObject.handleWebhookInvoke)(ctx, this.webhookStore, req, url);
|
|
878
900
|
if (webhookResponse) return webhookResponse;
|
|
879
901
|
if (url.pathname.startsWith("/api/")) {
|
|
902
|
+
if ("OPTIONS" === req.method) return withApiCors(new Response(null, {
|
|
903
|
+
status: 204
|
|
904
|
+
}));
|
|
880
905
|
if ("/api/config" === url.pathname) {
|
|
881
906
|
const agents = this.wingmanConfig.agents?.list?.map((agent)=>({
|
|
882
907
|
id: agent.id,
|
|
@@ -884,7 +909,7 @@ class GatewayServer {
|
|
|
884
909
|
default: agent.default
|
|
885
910
|
})) || [];
|
|
886
911
|
const defaultAgentId = this.router.selectAgent();
|
|
887
|
-
return new Response(JSON.stringify({
|
|
912
|
+
return withApiCors(new Response(JSON.stringify({
|
|
888
913
|
gatewayHost: this.config.host,
|
|
889
914
|
gatewayPort: this.config.port,
|
|
890
915
|
requireAuth: this.auth.isAuthRequired(),
|
|
@@ -897,15 +922,15 @@ class GatewayServer {
|
|
|
897
922
|
headers: {
|
|
898
923
|
"Content-Type": "application/json"
|
|
899
924
|
}
|
|
900
|
-
});
|
|
925
|
+
}));
|
|
901
926
|
}
|
|
902
927
|
const apiResponse = await (0, webhooks_cjs_namespaceObject.handleWebhooksApi)(ctx, this.webhookStore, req, url) || await (0, routines_cjs_namespaceObject.handleRoutinesApi)(ctx, this.routineStore, req, url) || await (0, agents_cjs_namespaceObject.handleAgentsApi)(ctx, req, url) || await (0, providers_cjs_namespaceObject.handleProvidersApi)(ctx, req, url) || await (0, voice_cjs_namespaceObject.handleVoiceApi)(ctx, req, url) || await (0, fs_cjs_namespaceObject.handleFsApi)(ctx, req, url) || await (0, sessions_cjs_namespaceObject.handleSessionsApi)(ctx, req, url);
|
|
903
|
-
if (apiResponse) return apiResponse;
|
|
904
|
-
if ("/api/health" === url.pathname) return this.handleHealthCheck();
|
|
905
|
-
if ("/api/stats" === url.pathname) return this.handleStats();
|
|
906
|
-
return new Response("Not Found", {
|
|
928
|
+
if (apiResponse) return withApiCors(apiResponse);
|
|
929
|
+
if ("/api/health" === url.pathname) return withApiCors(this.handleHealthCheck());
|
|
930
|
+
if ("/api/stats" === url.pathname) return withApiCors(this.handleStats());
|
|
931
|
+
return withApiCors(new Response("Not Found", {
|
|
907
932
|
status: 404
|
|
908
|
-
});
|
|
933
|
+
}));
|
|
909
934
|
}
|
|
910
935
|
if ("GET" !== req.method) return new Response("Method Not Allowed", {
|
|
911
936
|
status: 405
|
|
@@ -1158,11 +1183,20 @@ class GatewayServer {
|
|
|
1158
1183
|
}
|
|
1159
1184
|
function buildAttachmentPreview(attachments) {
|
|
1160
1185
|
if (!attachments || 0 === attachments.length) return "Attachment";
|
|
1186
|
+
let hasFile = false;
|
|
1161
1187
|
let hasAudio = false;
|
|
1162
1188
|
let hasImage = false;
|
|
1163
|
-
for (const attachment of attachments)
|
|
1164
|
-
|
|
1189
|
+
for (const attachment of attachments){
|
|
1190
|
+
if (isFileAttachment(attachment)) {
|
|
1191
|
+
hasFile = true;
|
|
1192
|
+
continue;
|
|
1193
|
+
}
|
|
1194
|
+
if (isAudioAttachment(attachment)) hasAudio = true;
|
|
1195
|
+
else hasImage = true;
|
|
1196
|
+
}
|
|
1165
1197
|
const count = attachments.length;
|
|
1198
|
+
if (hasFile && (hasAudio || hasImage)) return count > 1 ? "File and media attachments" : "File and media attachment";
|
|
1199
|
+
if (hasFile) return count > 1 ? "File attachments" : "File attachment";
|
|
1166
1200
|
if (hasAudio && hasImage) return count > 1 ? "Media attachments" : "Media attachment";
|
|
1167
1201
|
if (hasAudio) return count > 1 ? "Audio attachments" : "Audio attachment";
|
|
1168
1202
|
return count > 1 ? "Image attachments" : "Image attachment";
|
|
@@ -1173,6 +1207,10 @@ function isAudioAttachment(attachment) {
|
|
|
1173
1207
|
if (attachment.dataUrl?.startsWith("data:audio/")) return true;
|
|
1174
1208
|
return false;
|
|
1175
1209
|
}
|
|
1210
|
+
function isFileAttachment(attachment) {
|
|
1211
|
+
if ("file" === attachment.kind) return true;
|
|
1212
|
+
return "string" == typeof attachment.textContent;
|
|
1213
|
+
}
|
|
1176
1214
|
exports.GatewayServer = __webpack_exports__.GatewayServer;
|
|
1177
1215
|
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
1178
1216
|
"GatewayServer"
|