@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
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_exports__ = {};
|
|
3
|
+
const external_vitest_namespaceObject = require("vitest");
|
|
4
|
+
const agents_cjs_namespaceObject = require("../gateway/http/agents.cjs");
|
|
5
|
+
const external_node_fs_namespaceObject = require("node:fs");
|
|
6
|
+
const external_node_path_namespaceObject = require("node:path");
|
|
7
|
+
const external_node_os_namespaceObject = require("node:os");
|
|
8
|
+
const external_js_yaml_namespaceObject = require("js-yaml");
|
|
9
|
+
const isBunRuntime = void 0 !== globalThis.Bun;
|
|
10
|
+
const describeIfBun = isBunRuntime ? external_vitest_namespaceObject.describe : external_vitest_namespaceObject.describe.skip;
|
|
11
|
+
const parseMarkdownAgent = (raw)=>{
|
|
12
|
+
const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n?([\s\S]*)$/;
|
|
13
|
+
const match = raw.match(frontmatterRegex);
|
|
14
|
+
if (!match) throw new Error("Agent markdown is missing frontmatter");
|
|
15
|
+
const metadata = external_js_yaml_namespaceObject.load(match[1]) || {};
|
|
16
|
+
return {
|
|
17
|
+
metadata,
|
|
18
|
+
prompt: match[2].trim()
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
describeIfBun("agents API", ()=>{
|
|
22
|
+
let tempDir;
|
|
23
|
+
let config;
|
|
24
|
+
let ctx;
|
|
25
|
+
(0, external_vitest_namespaceObject.beforeEach)(()=>{
|
|
26
|
+
tempDir = (0, external_node_fs_namespaceObject.mkdtempSync)((0, external_node_path_namespaceObject.join)((0, external_node_os_namespaceObject.tmpdir)(), "wingman-agents-api-"));
|
|
27
|
+
config = {
|
|
28
|
+
agents: {
|
|
29
|
+
list: [],
|
|
30
|
+
bindings: []
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
ctx = {
|
|
34
|
+
workspace: tempDir,
|
|
35
|
+
configDir: tempDir,
|
|
36
|
+
getWingmanConfig: ()=>config,
|
|
37
|
+
setWingmanConfig: (next)=>{
|
|
38
|
+
config = next;
|
|
39
|
+
},
|
|
40
|
+
persistWingmanConfig: ()=>{},
|
|
41
|
+
router: {},
|
|
42
|
+
setRouter: ()=>{},
|
|
43
|
+
resolveConfigDirPath: ()=>tempDir,
|
|
44
|
+
getBuiltInTools: ()=>[]
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
(0, external_vitest_namespaceObject.afterEach)(()=>{
|
|
48
|
+
(0, external_node_fs_namespaceObject.rmSync)(tempDir, {
|
|
49
|
+
recursive: true,
|
|
50
|
+
force: true
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
(0, external_vitest_namespaceObject.it)("creates agent markdown with promptTraining and subAgents", async ()=>{
|
|
54
|
+
const createReq = new Request("http://localhost/api/agents", {
|
|
55
|
+
method: "POST",
|
|
56
|
+
headers: {
|
|
57
|
+
"Content-Type": "application/json"
|
|
58
|
+
},
|
|
59
|
+
body: JSON.stringify({
|
|
60
|
+
id: "orchestrator",
|
|
61
|
+
displayName: "Orchestrator",
|
|
62
|
+
description: "Delegates work",
|
|
63
|
+
tools: [
|
|
64
|
+
"think",
|
|
65
|
+
"not_real_tool"
|
|
66
|
+
],
|
|
67
|
+
prompt: "You are the orchestrator.",
|
|
68
|
+
promptTraining: {
|
|
69
|
+
enabled: true,
|
|
70
|
+
instructionsPath: "/memories/agents/orchestrator/instructions.md"
|
|
71
|
+
},
|
|
72
|
+
subAgents: [
|
|
73
|
+
{
|
|
74
|
+
id: "planner",
|
|
75
|
+
description: "Plans tasks",
|
|
76
|
+
tools: [
|
|
77
|
+
"think",
|
|
78
|
+
"not_real_tool"
|
|
79
|
+
],
|
|
80
|
+
prompt: "Plan tasks in detail.",
|
|
81
|
+
promptTraining: true
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: "executor",
|
|
85
|
+
description: "Executes tasks",
|
|
86
|
+
tools: [
|
|
87
|
+
"command_execute"
|
|
88
|
+
],
|
|
89
|
+
prompt: "Execute planned tasks."
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
})
|
|
93
|
+
});
|
|
94
|
+
const createRes = await (0, agents_cjs_namespaceObject.handleAgentsApi)(ctx, createReq, new URL(createReq.url));
|
|
95
|
+
(0, external_vitest_namespaceObject.expect)(createRes).not.toBeNull();
|
|
96
|
+
(0, external_vitest_namespaceObject.expect)(createRes?.ok).toBe(true);
|
|
97
|
+
const created = await createRes.json();
|
|
98
|
+
(0, external_vitest_namespaceObject.expect)(created.promptTraining).toEqual({
|
|
99
|
+
enabled: true,
|
|
100
|
+
instructionsPath: "/memories/agents/orchestrator/instructions.md"
|
|
101
|
+
});
|
|
102
|
+
(0, external_vitest_namespaceObject.expect)(created.promptRefinement).toEqual(created.promptTraining);
|
|
103
|
+
(0, external_vitest_namespaceObject.expect)(created.subAgents).toHaveLength(2);
|
|
104
|
+
(0, external_vitest_namespaceObject.expect)(created.subAgents[0].promptTraining).toBe(true);
|
|
105
|
+
(0, external_vitest_namespaceObject.expect)(created.subAgents[0].tools).toEqual([
|
|
106
|
+
"think"
|
|
107
|
+
]);
|
|
108
|
+
const agentPath = (0, external_node_path_namespaceObject.join)(tempDir, "agents", "orchestrator", "agent.md");
|
|
109
|
+
const parsed = parseMarkdownAgent((0, external_node_fs_namespaceObject.readFileSync)(agentPath, "utf-8"));
|
|
110
|
+
(0, external_vitest_namespaceObject.expect)(parsed.prompt).toBe("You are the orchestrator.");
|
|
111
|
+
(0, external_vitest_namespaceObject.expect)(parsed.metadata.promptRefinement).toEqual({
|
|
112
|
+
enabled: true,
|
|
113
|
+
instructionsPath: "/memories/agents/orchestrator/instructions.md"
|
|
114
|
+
});
|
|
115
|
+
(0, external_vitest_namespaceObject.expect)(parsed.metadata.subAgents).toHaveLength(2);
|
|
116
|
+
(0, external_vitest_namespaceObject.expect)(parsed.metadata.subAgents[0].name).toBe("planner");
|
|
117
|
+
(0, external_vitest_namespaceObject.expect)(parsed.metadata.subAgents[0].promptRefinement).toBe(true);
|
|
118
|
+
(0, external_vitest_namespaceObject.expect)(parsed.metadata.subAgents[0].systemPrompt).toBe("Plan tasks in detail.");
|
|
119
|
+
const detailReq = new Request("http://localhost/api/agents/orchestrator", {
|
|
120
|
+
method: "GET"
|
|
121
|
+
});
|
|
122
|
+
const detailRes = await (0, agents_cjs_namespaceObject.handleAgentsApi)(ctx, detailReq, new URL(detailReq.url));
|
|
123
|
+
(0, external_vitest_namespaceObject.expect)(detailRes).not.toBeNull();
|
|
124
|
+
(0, external_vitest_namespaceObject.expect)(detailRes?.ok).toBe(true);
|
|
125
|
+
const detail = await detailRes.json();
|
|
126
|
+
(0, external_vitest_namespaceObject.expect)(detail.promptTraining).toEqual(created.promptTraining);
|
|
127
|
+
(0, external_vitest_namespaceObject.expect)(detail.promptRefinement).toEqual(created.promptTraining);
|
|
128
|
+
(0, external_vitest_namespaceObject.expect)(detail.subAgents).toHaveLength(2);
|
|
129
|
+
(0, external_vitest_namespaceObject.expect)(detail.subAgents[0].id).toBe("planner");
|
|
130
|
+
(0, external_vitest_namespaceObject.expect)(detail.subAgents[0].prompt).toBe("Plan tasks in detail.");
|
|
131
|
+
});
|
|
132
|
+
(0, external_vitest_namespaceObject.it)("updates promptTraining and subAgents in markdown", async ()=>{
|
|
133
|
+
const createReq = new Request("http://localhost/api/agents", {
|
|
134
|
+
method: "POST",
|
|
135
|
+
headers: {
|
|
136
|
+
"Content-Type": "application/json"
|
|
137
|
+
},
|
|
138
|
+
body: JSON.stringify({
|
|
139
|
+
id: "editor-agent",
|
|
140
|
+
tools: [
|
|
141
|
+
"think"
|
|
142
|
+
],
|
|
143
|
+
prompt: "Original prompt",
|
|
144
|
+
promptTraining: true,
|
|
145
|
+
subAgents: [
|
|
146
|
+
{
|
|
147
|
+
id: "planner",
|
|
148
|
+
description: "Plans",
|
|
149
|
+
tools: [
|
|
150
|
+
"think"
|
|
151
|
+
],
|
|
152
|
+
prompt: "Original planner prompt"
|
|
153
|
+
}
|
|
154
|
+
]
|
|
155
|
+
})
|
|
156
|
+
});
|
|
157
|
+
const createRes = await (0, agents_cjs_namespaceObject.handleAgentsApi)(ctx, createReq, new URL(createReq.url));
|
|
158
|
+
(0, external_vitest_namespaceObject.expect)(createRes?.ok).toBe(true);
|
|
159
|
+
const updateReq = new Request("http://localhost/api/agents/editor-agent", {
|
|
160
|
+
method: "PUT",
|
|
161
|
+
headers: {
|
|
162
|
+
"Content-Type": "application/json"
|
|
163
|
+
},
|
|
164
|
+
body: JSON.stringify({
|
|
165
|
+
promptTraining: false,
|
|
166
|
+
subAgents: [
|
|
167
|
+
{
|
|
168
|
+
id: "reviewer",
|
|
169
|
+
description: "Reviews output",
|
|
170
|
+
tools: [
|
|
171
|
+
"git_status"
|
|
172
|
+
],
|
|
173
|
+
prompt: "Review carefully.",
|
|
174
|
+
promptTraining: {
|
|
175
|
+
enabled: true,
|
|
176
|
+
instructionsPath: "/memories/reviewer.md"
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
]
|
|
180
|
+
})
|
|
181
|
+
});
|
|
182
|
+
const updateRes = await (0, agents_cjs_namespaceObject.handleAgentsApi)(ctx, updateReq, new URL(updateReq.url));
|
|
183
|
+
(0, external_vitest_namespaceObject.expect)(updateRes).not.toBeNull();
|
|
184
|
+
if (updateRes && !updateRes.ok) throw new Error(await updateRes.text());
|
|
185
|
+
(0, external_vitest_namespaceObject.expect)(updateRes?.ok).toBe(true);
|
|
186
|
+
const updated = await updateRes.json();
|
|
187
|
+
(0, external_vitest_namespaceObject.expect)(updated.promptTraining).toBe(false);
|
|
188
|
+
(0, external_vitest_namespaceObject.expect)(updated.promptRefinement).toBe(false);
|
|
189
|
+
(0, external_vitest_namespaceObject.expect)(updated.subAgents).toHaveLength(1);
|
|
190
|
+
(0, external_vitest_namespaceObject.expect)(updated.subAgents[0].id).toBe("reviewer");
|
|
191
|
+
(0, external_vitest_namespaceObject.expect)(updated.subAgents[0].promptTraining).toEqual({
|
|
192
|
+
enabled: true,
|
|
193
|
+
instructionsPath: "/memories/reviewer.md"
|
|
194
|
+
});
|
|
195
|
+
const agentPath = (0, external_node_path_namespaceObject.join)(tempDir, "agents", "editor-agent", "agent.md");
|
|
196
|
+
const parsed = parseMarkdownAgent((0, external_node_fs_namespaceObject.readFileSync)(agentPath, "utf-8"));
|
|
197
|
+
(0, external_vitest_namespaceObject.expect)(parsed.metadata.promptRefinement).toBe(false);
|
|
198
|
+
(0, external_vitest_namespaceObject.expect)(parsed.metadata.subAgents).toHaveLength(1);
|
|
199
|
+
(0, external_vitest_namespaceObject.expect)(parsed.metadata.subAgents[0].name).toBe("reviewer");
|
|
200
|
+
(0, external_vitest_namespaceObject.expect)(parsed.metadata.subAgents[0].promptRefinement).toEqual({
|
|
201
|
+
enabled: true,
|
|
202
|
+
instructionsPath: "/memories/reviewer.md"
|
|
203
|
+
});
|
|
204
|
+
(0, external_vitest_namespaceObject.expect)(parsed.metadata.subAgents[0].systemPrompt).toBe("Review carefully.");
|
|
205
|
+
});
|
|
206
|
+
(0, external_vitest_namespaceObject.it)("accepts legacy promptRefinement input as promptTraining", async ()=>{
|
|
207
|
+
const createReq = new Request("http://localhost/api/agents", {
|
|
208
|
+
method: "POST",
|
|
209
|
+
headers: {
|
|
210
|
+
"Content-Type": "application/json"
|
|
211
|
+
},
|
|
212
|
+
body: JSON.stringify({
|
|
213
|
+
id: "legacy-agent",
|
|
214
|
+
tools: [
|
|
215
|
+
"think"
|
|
216
|
+
],
|
|
217
|
+
prompt: "Legacy prompt",
|
|
218
|
+
promptRefinement: true
|
|
219
|
+
})
|
|
220
|
+
});
|
|
221
|
+
const createRes = await (0, agents_cjs_namespaceObject.handleAgentsApi)(ctx, createReq, new URL(createReq.url));
|
|
222
|
+
(0, external_vitest_namespaceObject.expect)(createRes).not.toBeNull();
|
|
223
|
+
(0, external_vitest_namespaceObject.expect)(createRes?.ok).toBe(true);
|
|
224
|
+
const created = await createRes.json();
|
|
225
|
+
(0, external_vitest_namespaceObject.expect)(created.promptTraining).toBe(true);
|
|
226
|
+
(0, external_vitest_namespaceObject.expect)(created.promptRefinement).toBe(true);
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
for(var __rspack_i in __webpack_exports__)exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
230
|
+
Object.defineProperty(exports, '__esModule', {
|
|
231
|
+
value: true
|
|
232
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
2
|
+
import { handleAgentsApi } from "../gateway/http/agents.js";
|
|
3
|
+
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { load } from "js-yaml";
|
|
7
|
+
const isBunRuntime = void 0 !== globalThis.Bun;
|
|
8
|
+
const describeIfBun = isBunRuntime ? describe : describe.skip;
|
|
9
|
+
const parseMarkdownAgent = (raw)=>{
|
|
10
|
+
const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n?([\s\S]*)$/;
|
|
11
|
+
const match = raw.match(frontmatterRegex);
|
|
12
|
+
if (!match) throw new Error("Agent markdown is missing frontmatter");
|
|
13
|
+
const metadata = load(match[1]) || {};
|
|
14
|
+
return {
|
|
15
|
+
metadata,
|
|
16
|
+
prompt: match[2].trim()
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
describeIfBun("agents API", ()=>{
|
|
20
|
+
let tempDir;
|
|
21
|
+
let config;
|
|
22
|
+
let ctx;
|
|
23
|
+
beforeEach(()=>{
|
|
24
|
+
tempDir = mkdtempSync(join(tmpdir(), "wingman-agents-api-"));
|
|
25
|
+
config = {
|
|
26
|
+
agents: {
|
|
27
|
+
list: [],
|
|
28
|
+
bindings: []
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
ctx = {
|
|
32
|
+
workspace: tempDir,
|
|
33
|
+
configDir: tempDir,
|
|
34
|
+
getWingmanConfig: ()=>config,
|
|
35
|
+
setWingmanConfig: (next)=>{
|
|
36
|
+
config = next;
|
|
37
|
+
},
|
|
38
|
+
persistWingmanConfig: ()=>{},
|
|
39
|
+
router: {},
|
|
40
|
+
setRouter: ()=>{},
|
|
41
|
+
resolveConfigDirPath: ()=>tempDir,
|
|
42
|
+
getBuiltInTools: ()=>[]
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
afterEach(()=>{
|
|
46
|
+
rmSync(tempDir, {
|
|
47
|
+
recursive: true,
|
|
48
|
+
force: true
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
it("creates agent markdown with promptTraining and subAgents", async ()=>{
|
|
52
|
+
const createReq = new Request("http://localhost/api/agents", {
|
|
53
|
+
method: "POST",
|
|
54
|
+
headers: {
|
|
55
|
+
"Content-Type": "application/json"
|
|
56
|
+
},
|
|
57
|
+
body: JSON.stringify({
|
|
58
|
+
id: "orchestrator",
|
|
59
|
+
displayName: "Orchestrator",
|
|
60
|
+
description: "Delegates work",
|
|
61
|
+
tools: [
|
|
62
|
+
"think",
|
|
63
|
+
"not_real_tool"
|
|
64
|
+
],
|
|
65
|
+
prompt: "You are the orchestrator.",
|
|
66
|
+
promptTraining: {
|
|
67
|
+
enabled: true,
|
|
68
|
+
instructionsPath: "/memories/agents/orchestrator/instructions.md"
|
|
69
|
+
},
|
|
70
|
+
subAgents: [
|
|
71
|
+
{
|
|
72
|
+
id: "planner",
|
|
73
|
+
description: "Plans tasks",
|
|
74
|
+
tools: [
|
|
75
|
+
"think",
|
|
76
|
+
"not_real_tool"
|
|
77
|
+
],
|
|
78
|
+
prompt: "Plan tasks in detail.",
|
|
79
|
+
promptTraining: true
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
id: "executor",
|
|
83
|
+
description: "Executes tasks",
|
|
84
|
+
tools: [
|
|
85
|
+
"command_execute"
|
|
86
|
+
],
|
|
87
|
+
prompt: "Execute planned tasks."
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
})
|
|
91
|
+
});
|
|
92
|
+
const createRes = await handleAgentsApi(ctx, createReq, new URL(createReq.url));
|
|
93
|
+
expect(createRes).not.toBeNull();
|
|
94
|
+
expect(createRes?.ok).toBe(true);
|
|
95
|
+
const created = await createRes.json();
|
|
96
|
+
expect(created.promptTraining).toEqual({
|
|
97
|
+
enabled: true,
|
|
98
|
+
instructionsPath: "/memories/agents/orchestrator/instructions.md"
|
|
99
|
+
});
|
|
100
|
+
expect(created.promptRefinement).toEqual(created.promptTraining);
|
|
101
|
+
expect(created.subAgents).toHaveLength(2);
|
|
102
|
+
expect(created.subAgents[0].promptTraining).toBe(true);
|
|
103
|
+
expect(created.subAgents[0].tools).toEqual([
|
|
104
|
+
"think"
|
|
105
|
+
]);
|
|
106
|
+
const agentPath = join(tempDir, "agents", "orchestrator", "agent.md");
|
|
107
|
+
const parsed = parseMarkdownAgent(readFileSync(agentPath, "utf-8"));
|
|
108
|
+
expect(parsed.prompt).toBe("You are the orchestrator.");
|
|
109
|
+
expect(parsed.metadata.promptRefinement).toEqual({
|
|
110
|
+
enabled: true,
|
|
111
|
+
instructionsPath: "/memories/agents/orchestrator/instructions.md"
|
|
112
|
+
});
|
|
113
|
+
expect(parsed.metadata.subAgents).toHaveLength(2);
|
|
114
|
+
expect(parsed.metadata.subAgents[0].name).toBe("planner");
|
|
115
|
+
expect(parsed.metadata.subAgents[0].promptRefinement).toBe(true);
|
|
116
|
+
expect(parsed.metadata.subAgents[0].systemPrompt).toBe("Plan tasks in detail.");
|
|
117
|
+
const detailReq = new Request("http://localhost/api/agents/orchestrator", {
|
|
118
|
+
method: "GET"
|
|
119
|
+
});
|
|
120
|
+
const detailRes = await handleAgentsApi(ctx, detailReq, new URL(detailReq.url));
|
|
121
|
+
expect(detailRes).not.toBeNull();
|
|
122
|
+
expect(detailRes?.ok).toBe(true);
|
|
123
|
+
const detail = await detailRes.json();
|
|
124
|
+
expect(detail.promptTraining).toEqual(created.promptTraining);
|
|
125
|
+
expect(detail.promptRefinement).toEqual(created.promptTraining);
|
|
126
|
+
expect(detail.subAgents).toHaveLength(2);
|
|
127
|
+
expect(detail.subAgents[0].id).toBe("planner");
|
|
128
|
+
expect(detail.subAgents[0].prompt).toBe("Plan tasks in detail.");
|
|
129
|
+
});
|
|
130
|
+
it("updates promptTraining and subAgents in markdown", async ()=>{
|
|
131
|
+
const createReq = new Request("http://localhost/api/agents", {
|
|
132
|
+
method: "POST",
|
|
133
|
+
headers: {
|
|
134
|
+
"Content-Type": "application/json"
|
|
135
|
+
},
|
|
136
|
+
body: JSON.stringify({
|
|
137
|
+
id: "editor-agent",
|
|
138
|
+
tools: [
|
|
139
|
+
"think"
|
|
140
|
+
],
|
|
141
|
+
prompt: "Original prompt",
|
|
142
|
+
promptTraining: true,
|
|
143
|
+
subAgents: [
|
|
144
|
+
{
|
|
145
|
+
id: "planner",
|
|
146
|
+
description: "Plans",
|
|
147
|
+
tools: [
|
|
148
|
+
"think"
|
|
149
|
+
],
|
|
150
|
+
prompt: "Original planner prompt"
|
|
151
|
+
}
|
|
152
|
+
]
|
|
153
|
+
})
|
|
154
|
+
});
|
|
155
|
+
const createRes = await handleAgentsApi(ctx, createReq, new URL(createReq.url));
|
|
156
|
+
expect(createRes?.ok).toBe(true);
|
|
157
|
+
const updateReq = new Request("http://localhost/api/agents/editor-agent", {
|
|
158
|
+
method: "PUT",
|
|
159
|
+
headers: {
|
|
160
|
+
"Content-Type": "application/json"
|
|
161
|
+
},
|
|
162
|
+
body: JSON.stringify({
|
|
163
|
+
promptTraining: false,
|
|
164
|
+
subAgents: [
|
|
165
|
+
{
|
|
166
|
+
id: "reviewer",
|
|
167
|
+
description: "Reviews output",
|
|
168
|
+
tools: [
|
|
169
|
+
"git_status"
|
|
170
|
+
],
|
|
171
|
+
prompt: "Review carefully.",
|
|
172
|
+
promptTraining: {
|
|
173
|
+
enabled: true,
|
|
174
|
+
instructionsPath: "/memories/reviewer.md"
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
]
|
|
178
|
+
})
|
|
179
|
+
});
|
|
180
|
+
const updateRes = await handleAgentsApi(ctx, updateReq, new URL(updateReq.url));
|
|
181
|
+
expect(updateRes).not.toBeNull();
|
|
182
|
+
if (updateRes && !updateRes.ok) throw new Error(await updateRes.text());
|
|
183
|
+
expect(updateRes?.ok).toBe(true);
|
|
184
|
+
const updated = await updateRes.json();
|
|
185
|
+
expect(updated.promptTraining).toBe(false);
|
|
186
|
+
expect(updated.promptRefinement).toBe(false);
|
|
187
|
+
expect(updated.subAgents).toHaveLength(1);
|
|
188
|
+
expect(updated.subAgents[0].id).toBe("reviewer");
|
|
189
|
+
expect(updated.subAgents[0].promptTraining).toEqual({
|
|
190
|
+
enabled: true,
|
|
191
|
+
instructionsPath: "/memories/reviewer.md"
|
|
192
|
+
});
|
|
193
|
+
const agentPath = join(tempDir, "agents", "editor-agent", "agent.md");
|
|
194
|
+
const parsed = parseMarkdownAgent(readFileSync(agentPath, "utf-8"));
|
|
195
|
+
expect(parsed.metadata.promptRefinement).toBe(false);
|
|
196
|
+
expect(parsed.metadata.subAgents).toHaveLength(1);
|
|
197
|
+
expect(parsed.metadata.subAgents[0].name).toBe("reviewer");
|
|
198
|
+
expect(parsed.metadata.subAgents[0].promptRefinement).toEqual({
|
|
199
|
+
enabled: true,
|
|
200
|
+
instructionsPath: "/memories/reviewer.md"
|
|
201
|
+
});
|
|
202
|
+
expect(parsed.metadata.subAgents[0].systemPrompt).toBe("Review carefully.");
|
|
203
|
+
});
|
|
204
|
+
it("accepts legacy promptRefinement input as promptTraining", async ()=>{
|
|
205
|
+
const createReq = new Request("http://localhost/api/agents", {
|
|
206
|
+
method: "POST",
|
|
207
|
+
headers: {
|
|
208
|
+
"Content-Type": "application/json"
|
|
209
|
+
},
|
|
210
|
+
body: JSON.stringify({
|
|
211
|
+
id: "legacy-agent",
|
|
212
|
+
tools: [
|
|
213
|
+
"think"
|
|
214
|
+
],
|
|
215
|
+
prompt: "Legacy prompt",
|
|
216
|
+
promptRefinement: true
|
|
217
|
+
})
|
|
218
|
+
});
|
|
219
|
+
const createRes = await handleAgentsApi(ctx, createReq, new URL(createReq.url));
|
|
220
|
+
expect(createRes).not.toBeNull();
|
|
221
|
+
expect(createRes?.ok).toBe(true);
|
|
222
|
+
const created = await createRes.json();
|
|
223
|
+
expect(created.promptTraining).toBe(true);
|
|
224
|
+
expect(created.promptRefinement).toBe(true);
|
|
225
|
+
});
|
|
226
|
+
});
|
|
@@ -275,6 +275,27 @@ describeIfBun("Gateway", ()=>{
|
|
|
275
275
|
webuiClient.close();
|
|
276
276
|
requester.close();
|
|
277
277
|
});
|
|
278
|
+
(0, external_vitest_namespaceObject.it)("should broadcast user messages to desktop clients without session subscribe", async ()=>{
|
|
279
|
+
const desktopClient = await connectClient("session-desktop-listener", "desktop");
|
|
280
|
+
const requester = await connectClient("session-desktop-requester");
|
|
281
|
+
const sessionId = "session-desktop-test";
|
|
282
|
+
const eventPromise = waitForMessage(desktopClient, (msg)=>"event:agent" === msg.type && msg.payload?.type === "session-message" && msg.payload?.role === "user" && msg.payload?.sessionId === sessionId);
|
|
283
|
+
requester.send(JSON.stringify({
|
|
284
|
+
type: "req:agent",
|
|
285
|
+
id: "req-session-desktop",
|
|
286
|
+
payload: {
|
|
287
|
+
agentId: "main",
|
|
288
|
+
sessionKey: sessionId,
|
|
289
|
+
content: "Hello desktop"
|
|
290
|
+
},
|
|
291
|
+
timestamp: Date.now()
|
|
292
|
+
}));
|
|
293
|
+
const eventMsg = await eventPromise;
|
|
294
|
+
(0, external_vitest_namespaceObject.expect)(eventMsg.payload?.content).toBe("Hello desktop");
|
|
295
|
+
(0, external_vitest_namespaceObject.expect)(eventMsg.payload?.agentId).toBe("main");
|
|
296
|
+
desktopClient.close();
|
|
297
|
+
requester.close();
|
|
298
|
+
});
|
|
278
299
|
(0, external_vitest_namespaceObject.it)("should clear session messages via API", async ()=>{
|
|
279
300
|
const createRes = await fetch(`http://localhost:${port}/api/sessions`, {
|
|
280
301
|
method: "POST",
|
|
@@ -273,6 +273,27 @@ describeIfBun("Gateway", ()=>{
|
|
|
273
273
|
webuiClient.close();
|
|
274
274
|
requester.close();
|
|
275
275
|
});
|
|
276
|
+
it("should broadcast user messages to desktop clients without session subscribe", async ()=>{
|
|
277
|
+
const desktopClient = await connectClient("session-desktop-listener", "desktop");
|
|
278
|
+
const requester = await connectClient("session-desktop-requester");
|
|
279
|
+
const sessionId = "session-desktop-test";
|
|
280
|
+
const eventPromise = waitForMessage(desktopClient, (msg)=>"event:agent" === msg.type && msg.payload?.type === "session-message" && msg.payload?.role === "user" && msg.payload?.sessionId === sessionId);
|
|
281
|
+
requester.send(JSON.stringify({
|
|
282
|
+
type: "req:agent",
|
|
283
|
+
id: "req-session-desktop",
|
|
284
|
+
payload: {
|
|
285
|
+
agentId: "main",
|
|
286
|
+
sessionKey: sessionId,
|
|
287
|
+
content: "Hello desktop"
|
|
288
|
+
},
|
|
289
|
+
timestamp: Date.now()
|
|
290
|
+
}));
|
|
291
|
+
const eventMsg = await eventPromise;
|
|
292
|
+
expect(eventMsg.payload?.content).toBe("Hello desktop");
|
|
293
|
+
expect(eventMsg.payload?.agentId).toBe("main");
|
|
294
|
+
desktopClient.close();
|
|
295
|
+
requester.close();
|
|
296
|
+
});
|
|
276
297
|
it("should clear session messages via API", async ()=>{
|
|
277
298
|
const createRes = await fetch(`http://localhost:${port}/api/sessions`, {
|
|
278
299
|
method: "POST",
|
|
@@ -101,6 +101,65 @@ const sessionManager_cjs_namespaceObject = require("../cli/core/sessionManager.c
|
|
|
101
101
|
}
|
|
102
102
|
]);
|
|
103
103
|
});
|
|
104
|
+
(0, external_vitest_namespaceObject.it)("extracts standardized base64 file blocks", ()=>{
|
|
105
|
+
const blocks = [
|
|
106
|
+
{
|
|
107
|
+
type: "file",
|
|
108
|
+
source_type: "base64",
|
|
109
|
+
data: "JVBERi0xLjQK",
|
|
110
|
+
mime_type: "application/pdf",
|
|
111
|
+
metadata: {
|
|
112
|
+
filename: "report.pdf"
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
];
|
|
116
|
+
(0, external_vitest_namespaceObject.expect)((0, sessionManager_cjs_namespaceObject.extractAttachments)(blocks)).toEqual([
|
|
117
|
+
{
|
|
118
|
+
kind: "file",
|
|
119
|
+
dataUrl: "data:application/pdf;base64,JVBERi0xLjQK",
|
|
120
|
+
name: "report.pdf",
|
|
121
|
+
mimeType: "application/pdf"
|
|
122
|
+
}
|
|
123
|
+
]);
|
|
124
|
+
});
|
|
125
|
+
(0, external_vitest_namespaceObject.it)("extracts input_file blocks", ()=>{
|
|
126
|
+
const blocks = [
|
|
127
|
+
{
|
|
128
|
+
type: "input_file",
|
|
129
|
+
file_data: "data:application/pdf;base64,JVBERi0xLjQK",
|
|
130
|
+
filename: "invoice.pdf"
|
|
131
|
+
}
|
|
132
|
+
];
|
|
133
|
+
(0, external_vitest_namespaceObject.expect)((0, sessionManager_cjs_namespaceObject.extractAttachments)(blocks)).toEqual([
|
|
134
|
+
{
|
|
135
|
+
kind: "file",
|
|
136
|
+
dataUrl: "data:application/pdf;base64,JVBERi0xLjQK",
|
|
137
|
+
name: "invoice.pdf",
|
|
138
|
+
mimeType: "application/pdf"
|
|
139
|
+
}
|
|
140
|
+
]);
|
|
141
|
+
});
|
|
142
|
+
(0, external_vitest_namespaceObject.it)("extracts anthropic document blocks", ()=>{
|
|
143
|
+
const blocks = [
|
|
144
|
+
{
|
|
145
|
+
type: "document",
|
|
146
|
+
title: "scan.pdf",
|
|
147
|
+
source: {
|
|
148
|
+
type: "base64",
|
|
149
|
+
media_type: "application/pdf",
|
|
150
|
+
data: "JVBERi0xLjQK"
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
];
|
|
154
|
+
(0, external_vitest_namespaceObject.expect)((0, sessionManager_cjs_namespaceObject.extractAttachments)(blocks)).toEqual([
|
|
155
|
+
{
|
|
156
|
+
kind: "file",
|
|
157
|
+
dataUrl: "data:application/pdf;base64,JVBERi0xLjQK",
|
|
158
|
+
name: "scan.pdf",
|
|
159
|
+
mimeType: "application/pdf"
|
|
160
|
+
}
|
|
161
|
+
]);
|
|
162
|
+
});
|
|
104
163
|
});
|
|
105
164
|
for(var __rspack_i in __webpack_exports__)exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
106
165
|
Object.defineProperty(exports, '__esModule', {
|
|
@@ -99,4 +99,63 @@ describe("extractAttachments", ()=>{
|
|
|
99
99
|
}
|
|
100
100
|
]);
|
|
101
101
|
});
|
|
102
|
+
it("extracts standardized base64 file blocks", ()=>{
|
|
103
|
+
const blocks = [
|
|
104
|
+
{
|
|
105
|
+
type: "file",
|
|
106
|
+
source_type: "base64",
|
|
107
|
+
data: "JVBERi0xLjQK",
|
|
108
|
+
mime_type: "application/pdf",
|
|
109
|
+
metadata: {
|
|
110
|
+
filename: "report.pdf"
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
];
|
|
114
|
+
expect(extractAttachments(blocks)).toEqual([
|
|
115
|
+
{
|
|
116
|
+
kind: "file",
|
|
117
|
+
dataUrl: "data:application/pdf;base64,JVBERi0xLjQK",
|
|
118
|
+
name: "report.pdf",
|
|
119
|
+
mimeType: "application/pdf"
|
|
120
|
+
}
|
|
121
|
+
]);
|
|
122
|
+
});
|
|
123
|
+
it("extracts input_file blocks", ()=>{
|
|
124
|
+
const blocks = [
|
|
125
|
+
{
|
|
126
|
+
type: "input_file",
|
|
127
|
+
file_data: "data:application/pdf;base64,JVBERi0xLjQK",
|
|
128
|
+
filename: "invoice.pdf"
|
|
129
|
+
}
|
|
130
|
+
];
|
|
131
|
+
expect(extractAttachments(blocks)).toEqual([
|
|
132
|
+
{
|
|
133
|
+
kind: "file",
|
|
134
|
+
dataUrl: "data:application/pdf;base64,JVBERi0xLjQK",
|
|
135
|
+
name: "invoice.pdf",
|
|
136
|
+
mimeType: "application/pdf"
|
|
137
|
+
}
|
|
138
|
+
]);
|
|
139
|
+
});
|
|
140
|
+
it("extracts anthropic document blocks", ()=>{
|
|
141
|
+
const blocks = [
|
|
142
|
+
{
|
|
143
|
+
type: "document",
|
|
144
|
+
title: "scan.pdf",
|
|
145
|
+
source: {
|
|
146
|
+
type: "base64",
|
|
147
|
+
media_type: "application/pdf",
|
|
148
|
+
data: "JVBERi0xLjQK"
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
];
|
|
152
|
+
expect(extractAttachments(blocks)).toEqual([
|
|
153
|
+
{
|
|
154
|
+
kind: "file",
|
|
155
|
+
dataUrl: "data:application/pdf;base64,JVBERi0xLjQK",
|
|
156
|
+
name: "scan.pdf",
|
|
157
|
+
mimeType: "application/pdf"
|
|
158
|
+
}
|
|
159
|
+
]);
|
|
160
|
+
});
|
|
102
161
|
});
|
package/dist/types/agents.d.ts
CHANGED
|
@@ -7,6 +7,10 @@ export type WingmanAgentTool = {
|
|
|
7
7
|
schema?: unknown;
|
|
8
8
|
invoke?: (...args: any[]) => unknown;
|
|
9
9
|
};
|
|
10
|
+
export type PromptRefinementConfig = {
|
|
11
|
+
enabled?: boolean;
|
|
12
|
+
instructionsPath?: string;
|
|
13
|
+
};
|
|
10
14
|
export type WingmanAgent = {
|
|
11
15
|
name: string;
|
|
12
16
|
systemPrompt: string;
|
|
@@ -19,4 +23,5 @@ export type WingmanAgent = {
|
|
|
19
23
|
mcpConfig?: MCPServersConfig;
|
|
20
24
|
mcpUseGlobal?: boolean;
|
|
21
25
|
voice?: AgentVoiceConfig;
|
|
26
|
+
promptRefinement?: PromptRefinementConfig;
|
|
22
27
|
};
|