@wingman-ai/gateway 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -111
- package/dist/agent/config/agentConfig.cjs +2 -0
- package/dist/agent/config/agentConfig.d.ts +6 -0
- package/dist/agent/config/agentConfig.js +2 -0
- package/dist/agent/config/agentLoader.cjs +21 -18
- package/dist/agent/config/agentLoader.js +22 -19
- package/dist/agent/config/toolRegistry.cjs +19 -0
- package/dist/agent/config/toolRegistry.d.ts +4 -0
- package/dist/agent/config/toolRegistry.js +17 -1
- package/dist/agent/middleware/additional-messages.cjs +115 -11
- package/dist/agent/middleware/additional-messages.d.ts +9 -0
- package/dist/agent/middleware/additional-messages.js +115 -11
- package/dist/agent/tests/agentLoader.test.cjs +45 -0
- package/dist/agent/tests/agentLoader.test.js +45 -0
- package/dist/agent/tests/toolRegistry.test.cjs +2 -0
- package/dist/agent/tests/toolRegistry.test.js +2 -0
- package/dist/agent/tools/node_invoke.cjs +146 -0
- package/dist/agent/tools/node_invoke.d.ts +86 -0
- package/dist/agent/tools/node_invoke.js +109 -0
- package/dist/cli/commands/gateway.cjs +1 -1
- package/dist/cli/commands/gateway.js +1 -1
- package/dist/cli/commands/init.cjs +135 -1
- package/dist/cli/commands/init.js +136 -2
- package/dist/cli/commands/skill.cjs +7 -3
- package/dist/cli/commands/skill.js +7 -3
- package/dist/cli/config/loader.cjs +7 -3
- package/dist/cli/config/loader.js +7 -3
- package/dist/cli/config/schema.cjs +27 -9
- package/dist/cli/config/schema.d.ts +18 -4
- package/dist/cli/config/schema.js +23 -8
- package/dist/cli/core/agentInvoker.cjs +70 -14
- package/dist/cli/core/agentInvoker.d.ts +10 -0
- package/dist/cli/core/agentInvoker.js +70 -14
- package/dist/cli/services/skillRepository.cjs +155 -69
- package/dist/cli/services/skillRepository.d.ts +7 -2
- package/dist/cli/services/skillRepository.js +155 -69
- package/dist/cli/services/skillService.cjs +93 -26
- package/dist/cli/services/skillService.d.ts +7 -0
- package/dist/cli/services/skillService.js +96 -29
- package/dist/cli/types/skill.d.ts +8 -3
- package/dist/gateway/http/nodes.cjs +247 -0
- package/dist/gateway/http/nodes.d.ts +20 -0
- package/dist/gateway/http/nodes.js +210 -0
- package/dist/gateway/node.cjs +10 -1
- package/dist/gateway/node.d.ts +10 -1
- package/dist/gateway/node.js +10 -1
- package/dist/gateway/server.cjs +414 -27
- package/dist/gateway/server.d.ts +34 -0
- package/dist/gateway/server.js +408 -27
- package/dist/gateway/types.d.ts +6 -1
- package/dist/gateway/validation.cjs +2 -0
- package/dist/gateway/validation.d.ts +4 -0
- package/dist/gateway/validation.js +2 -0
- package/dist/skills/activation.cjs +92 -0
- package/dist/skills/activation.d.ts +12 -0
- package/dist/skills/activation.js +58 -0
- package/dist/skills/bin-requirements.cjs +63 -0
- package/dist/skills/bin-requirements.d.ts +3 -0
- package/dist/skills/bin-requirements.js +26 -0
- package/dist/skills/metadata.cjs +141 -0
- package/dist/skills/metadata.d.ts +29 -0
- package/dist/skills/metadata.js +104 -0
- package/dist/skills/overlay.cjs +75 -0
- package/dist/skills/overlay.d.ts +2 -0
- package/dist/skills/overlay.js +38 -0
- package/dist/tests/additionalMessageMiddleware.test.cjs +92 -0
- package/dist/tests/additionalMessageMiddleware.test.js +92 -0
- package/dist/tests/cli-config-loader.test.cjs +7 -3
- package/dist/tests/cli-config-loader.test.js +7 -3
- package/dist/tests/cli-init.test.cjs +54 -0
- package/dist/tests/cli-init.test.js +54 -0
- package/dist/tests/config-json-schema.test.cjs +12 -0
- package/dist/tests/config-json-schema.test.js +12 -0
- package/dist/tests/gateway-http-security.test.cjs +277 -0
- package/dist/tests/gateway-http-security.test.d.ts +1 -0
- package/dist/tests/gateway-http-security.test.js +271 -0
- package/dist/tests/gateway-node-mode.test.cjs +174 -0
- package/dist/tests/gateway-node-mode.test.d.ts +1 -0
- package/dist/tests/gateway-node-mode.test.js +168 -0
- package/dist/tests/gateway-origin-policy.test.cjs +60 -0
- package/dist/tests/gateway-origin-policy.test.d.ts +1 -0
- package/dist/tests/gateway-origin-policy.test.js +54 -0
- package/dist/tests/gateway.test.cjs +1 -0
- package/dist/tests/gateway.test.js +1 -0
- package/dist/tests/node-tools.test.cjs +77 -0
- package/dist/tests/node-tools.test.d.ts +1 -0
- package/dist/tests/node-tools.test.js +71 -0
- package/dist/tests/nodes-api.test.cjs +86 -0
- package/dist/tests/nodes-api.test.d.ts +1 -0
- package/dist/tests/nodes-api.test.js +80 -0
- package/dist/tests/skill-activation.test.cjs +86 -0
- package/dist/tests/skill-activation.test.d.ts +1 -0
- package/dist/tests/skill-activation.test.js +80 -0
- package/dist/tests/skill-metadata.test.cjs +119 -0
- package/dist/tests/skill-metadata.test.d.ts +1 -0
- package/dist/tests/skill-metadata.test.js +113 -0
- package/dist/tests/skill-repository.test.cjs +363 -0
- package/dist/tests/skill-repository.test.js +363 -0
- package/dist/webui/assets/{index-DHbfLOUR.js → index-BMekSELC.js} +106 -106
- package/dist/webui/index.html +1 -1
- package/package.json +4 -4
- package/skills/gog/SKILL.md +1 -1
- package/skills/weather/SKILL.md +1 -1
- package/skills/ui-registry/SKILL.md +0 -35
|
@@ -2,6 +2,7 @@ import { isAbsolute, relative } from "node:path";
|
|
|
2
2
|
import { HumanMessage, MIDDLEWARE_BRAND } from "langchain";
|
|
3
3
|
import { getConfidentialityNotice } from "../utils.js";
|
|
4
4
|
import { loadUiRegistry, resolveUiRegistryPath, summarizeUiRegistry } from "../uiRegistry.js";
|
|
5
|
+
const INJECTION_SOURCE = "additional-message-middleware";
|
|
5
6
|
const normalizeRelativePath = (value)=>value.replace(/\\/g, "/");
|
|
6
7
|
const toSafeRelativePath = (workspaceRoot, targetPath)=>{
|
|
7
8
|
if (!workspaceRoot) return null;
|
|
@@ -28,12 +29,108 @@ const buildWorkingDirectoryMessage = (context)=>{
|
|
|
28
29
|
if (!context.workspaceRoot) return null;
|
|
29
30
|
return "** Working Directory **\n- Treat `./` as the current working directory for file and tool operations in this session.\n- Use relative paths such as `./test.md`; do not prepend the working directory absolute path.";
|
|
30
31
|
};
|
|
32
|
+
const resolveConnectedNodeIds = async (context)=>{
|
|
33
|
+
if (context.nodeConnectedTargetsProvider) try {
|
|
34
|
+
const rawTargets = await context.nodeConnectedTargetsProvider();
|
|
35
|
+
if (!Array.isArray(rawTargets)) return [];
|
|
36
|
+
const seen = new Set();
|
|
37
|
+
const normalized = [];
|
|
38
|
+
for (const target of rawTargets){
|
|
39
|
+
if (!target || "object" != typeof target) continue;
|
|
40
|
+
const nodeId = target.nodeId?.trim();
|
|
41
|
+
if (!(!nodeId || seen.has(nodeId))) {
|
|
42
|
+
seen.add(nodeId);
|
|
43
|
+
normalized.push(nodeId);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return normalized;
|
|
47
|
+
} catch {
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
if (!context.nodeConnectedIdsProvider) return [];
|
|
51
|
+
try {
|
|
52
|
+
const rawIds = await context.nodeConnectedIdsProvider();
|
|
53
|
+
if (!Array.isArray(rawIds)) return [];
|
|
54
|
+
const seen = new Set();
|
|
55
|
+
const normalized = [];
|
|
56
|
+
for (const value of rawIds){
|
|
57
|
+
if ("string" != typeof value) continue;
|
|
58
|
+
const trimmed = value.trim();
|
|
59
|
+
if (!(!trimmed || seen.has(trimmed))) {
|
|
60
|
+
seen.add(trimmed);
|
|
61
|
+
normalized.push(trimmed);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return normalized;
|
|
65
|
+
} catch {
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const resolveConnectedNodeTargets = async (context)=>{
|
|
70
|
+
if (context.nodeConnectedTargetsProvider) try {
|
|
71
|
+
const rawTargets = await context.nodeConnectedTargetsProvider();
|
|
72
|
+
if (!Array.isArray(rawTargets)) return [];
|
|
73
|
+
const seen = new Set();
|
|
74
|
+
const normalized = [];
|
|
75
|
+
for (const target of rawTargets){
|
|
76
|
+
if (!target || "object" != typeof target) continue;
|
|
77
|
+
const typedTarget = target;
|
|
78
|
+
const nodeId = typedTarget.nodeId?.trim();
|
|
79
|
+
if (!nodeId || seen.has(nodeId)) continue;
|
|
80
|
+
seen.add(nodeId);
|
|
81
|
+
const rawCapabilities = typedTarget.capabilities;
|
|
82
|
+
const capabilities = Array.isArray(rawCapabilities) ? rawCapabilities.filter((value)=>"string" == typeof value).map((value)=>value.trim()).filter(Boolean) : [];
|
|
83
|
+
normalized.push({
|
|
84
|
+
nodeId,
|
|
85
|
+
clientId: typedTarget.clientId?.trim() || void 0,
|
|
86
|
+
name: typedTarget.name?.trim() || void 0,
|
|
87
|
+
capabilities: capabilities.length > 0 ? capabilities : void 0
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return normalized;
|
|
91
|
+
} catch {
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
const nodeIds = await resolveConnectedNodeIds(context);
|
|
95
|
+
return nodeIds.map((nodeId)=>({
|
|
96
|
+
nodeId
|
|
97
|
+
}));
|
|
98
|
+
};
|
|
99
|
+
const buildNodeTargetsMessage = async (context)=>{
|
|
100
|
+
const connectedNodeTargets = await resolveConnectedNodeTargets(context);
|
|
101
|
+
const connectedNodeIds = connectedNodeTargets.map((target)=>target.nodeId);
|
|
102
|
+
const defaultClientId = context.defaultNodeTargetClientId?.trim();
|
|
103
|
+
if (0 === connectedNodeIds.length && !defaultClientId) return null;
|
|
104
|
+
const lines = [
|
|
105
|
+
"** Connected Node Targets **"
|
|
106
|
+
];
|
|
107
|
+
if (connectedNodeIds.length > 0) lines.push(`- Connected node IDs: ${connectedNodeIds.join(", ")}`);
|
|
108
|
+
else lines.push("- Connected node IDs: (none currently connected)");
|
|
109
|
+
const withMetadata = connectedNodeTargets.filter((target)=>Boolean(target.clientId) || Boolean(target.name) || target.capabilities && target.capabilities.length > 0);
|
|
110
|
+
if (withMetadata.length > 0) {
|
|
111
|
+
lines.push("- Connected node metadata:");
|
|
112
|
+
for (const target of withMetadata.slice(0, 8)){
|
|
113
|
+
const details = [];
|
|
114
|
+
if (target.clientId) details.push(`clientId: ${target.clientId}`);
|
|
115
|
+
if (target.name) details.push(`name: ${target.name}`);
|
|
116
|
+
if (target.capabilities && target.capabilities.length > 0) {
|
|
117
|
+
const preview = target.capabilities.slice(0, 6).join(", ");
|
|
118
|
+
const remaining = target.capabilities.length - 6;
|
|
119
|
+
details.push(remaining > 0 ? `capabilities: ${preview} (+${remaining} more)` : `capabilities: ${preview}`);
|
|
120
|
+
}
|
|
121
|
+
if (details.length > 0) lines.push(` - ${target.nodeId} (${details.join("; ")})`);
|
|
122
|
+
}
|
|
123
|
+
if (withMetadata.length > 8) lines.push(` - ... ${withMetadata.length - 8} more connected node(s)`);
|
|
124
|
+
}
|
|
125
|
+
if (defaultClientId) lines.push(`- Default node target clientId for this request: ${defaultClientId}`);
|
|
126
|
+
lines.push("- For node_notify/node_run, set target.nodeId or target.clientId when the user specifies a device.");
|
|
127
|
+
return lines.join("\n");
|
|
128
|
+
};
|
|
31
129
|
const additionalMessageMiddleware = (context = {})=>({
|
|
32
|
-
name:
|
|
130
|
+
name: INJECTION_SOURCE,
|
|
33
131
|
[MIDDLEWARE_BRAND]: true,
|
|
34
132
|
beforeAgent: async (input)=>{
|
|
35
|
-
const
|
|
36
|
-
if (alreadyInjected) return input;
|
|
133
|
+
const messagesWithoutInjected = input.messages.filter((message)=>message?.additional_kwargs?.source !== INJECTION_SOURCE);
|
|
37
134
|
const lines = [
|
|
38
135
|
getConfidentialityNotice(),
|
|
39
136
|
`** Current Date Time (UTC): ${new Date().toISOString()} **`
|
|
@@ -42,6 +139,8 @@ const additionalMessageMiddleware = (context = {})=>({
|
|
|
42
139
|
if (outputLocation) lines.push(outputLocation);
|
|
43
140
|
const workingDirectory = buildWorkingDirectoryMessage(context);
|
|
44
141
|
if (workingDirectory) lines.push(workingDirectory);
|
|
142
|
+
const nodeTargets = await buildNodeTargetsMessage(context);
|
|
143
|
+
if (nodeTargets) lines.push(nodeTargets);
|
|
45
144
|
lines.push("** Long-term memory **\n- Use /memories/ for durable notes across threads.\n- Store stable preferences, project context, decisions, and research notes.\n- Avoid transient logs; keep entries concise and organized.\n- Suggested paths: /memories/preferences.md, /memories/projects/<name>/context.md, /memories/projects/<name>/decisions.md");
|
|
46
145
|
if (false === context.dynamicUiEnabled) lines.push("** Dynamic UI **\n- Dynamic UI rendering is disabled for this gateway.\n- Respond with plain text and avoid calling UI presentation tools.");
|
|
47
146
|
else {
|
|
@@ -54,14 +153,19 @@ const additionalMessageMiddleware = (context = {})=>({
|
|
|
54
153
|
lines.push("** Dynamic UI Registry **\n" + summaryLines + "\n- Use ui_registry_get for schema details, then ui_present with textFallback.");
|
|
55
154
|
}
|
|
56
155
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
156
|
+
return {
|
|
157
|
+
...input,
|
|
158
|
+
messages: [
|
|
159
|
+
new HumanMessage({
|
|
160
|
+
content: lines.join("\n\n"),
|
|
161
|
+
additional_kwargs: {
|
|
162
|
+
ui_hidden: true,
|
|
163
|
+
source: INJECTION_SOURCE
|
|
164
|
+
}
|
|
165
|
+
}),
|
|
166
|
+
...messagesWithoutInjected
|
|
167
|
+
]
|
|
168
|
+
};
|
|
65
169
|
}
|
|
66
170
|
});
|
|
67
171
|
export { additionalMessageMiddleware };
|
|
@@ -197,6 +197,51 @@ Markdown agent`;
|
|
|
197
197
|
});
|
|
198
198
|
});
|
|
199
199
|
(0, external_vitest_namespaceObject.describe)("loadAgent", ()=>{
|
|
200
|
+
(0, external_vitest_namespaceObject.it)("should always inject node tools for top-level agents", async ()=>{
|
|
201
|
+
const agentDir = (0, external_node_path_namespaceObject.join)(TEST_CONFIG_DIR, "agents", "node-enabled-agent");
|
|
202
|
+
(0, external_node_fs_namespaceObject.mkdirSync)(agentDir, {
|
|
203
|
+
recursive: true
|
|
204
|
+
});
|
|
205
|
+
const config = {
|
|
206
|
+
name: "node-enabled-agent",
|
|
207
|
+
description: "Agent with default node tools",
|
|
208
|
+
systemPrompt: "You are node capable"
|
|
209
|
+
};
|
|
210
|
+
(0, external_node_fs_namespaceObject.writeFileSync)((0, external_node_path_namespaceObject.join)(agentDir, "agent.json"), JSON.stringify(config));
|
|
211
|
+
const loader = new agentLoader_cjs_namespaceObject.AgentLoader(TEST_CONFIG_DIR);
|
|
212
|
+
const agent = await loader.loadAgent("node-enabled-agent");
|
|
213
|
+
const toolNames = (agent?.tools || []).map((tool)=>tool.name);
|
|
214
|
+
(0, external_vitest_namespaceObject.expect)(toolNames).toContain("node_notify");
|
|
215
|
+
(0, external_vitest_namespaceObject.expect)(toolNames).toContain("node_run");
|
|
216
|
+
});
|
|
217
|
+
(0, external_vitest_namespaceObject.it)("should always inject and deduplicate node tools for subagents", async ()=>{
|
|
218
|
+
const agentDir = (0, external_node_path_namespaceObject.join)(TEST_CONFIG_DIR, "agents", "node-subagent-parent");
|
|
219
|
+
(0, external_node_fs_namespaceObject.mkdirSync)(agentDir, {
|
|
220
|
+
recursive: true
|
|
221
|
+
});
|
|
222
|
+
const config = {
|
|
223
|
+
name: "node-subagent-parent",
|
|
224
|
+
description: "Parent agent",
|
|
225
|
+
systemPrompt: "You are the parent",
|
|
226
|
+
subAgents: [
|
|
227
|
+
{
|
|
228
|
+
name: "node-subagent",
|
|
229
|
+
description: "Subagent",
|
|
230
|
+
systemPrompt: "You are a subagent",
|
|
231
|
+
tools: [
|
|
232
|
+
"node_run"
|
|
233
|
+
]
|
|
234
|
+
}
|
|
235
|
+
]
|
|
236
|
+
};
|
|
237
|
+
(0, external_node_fs_namespaceObject.writeFileSync)((0, external_node_path_namespaceObject.join)(agentDir, "agent.json"), JSON.stringify(config));
|
|
238
|
+
const loader = new agentLoader_cjs_namespaceObject.AgentLoader(TEST_CONFIG_DIR);
|
|
239
|
+
const agent = await loader.loadAgent("node-subagent-parent");
|
|
240
|
+
const sub = agent?.subagents?.[0];
|
|
241
|
+
const toolNames = (sub?.tools || []).map((tool)=>tool.name);
|
|
242
|
+
(0, external_vitest_namespaceObject.expect)(toolNames).toContain("node_notify");
|
|
243
|
+
(0, external_vitest_namespaceObject.expect)(toolNames.filter((name)=>"node_run" === name)).toHaveLength(1);
|
|
244
|
+
});
|
|
200
245
|
(0, external_vitest_namespaceObject.it)("should hydrate subagent tools for runtime use", async ()=>{
|
|
201
246
|
const agentDir = (0, external_node_path_namespaceObject.join)(TEST_CONFIG_DIR, "agents", "parent-agent");
|
|
202
247
|
(0, external_node_fs_namespaceObject.mkdirSync)(agentDir, {
|
|
@@ -195,6 +195,51 @@ Markdown agent`;
|
|
|
195
195
|
});
|
|
196
196
|
});
|
|
197
197
|
describe("loadAgent", ()=>{
|
|
198
|
+
it("should always inject node tools for top-level agents", async ()=>{
|
|
199
|
+
const agentDir = join(TEST_CONFIG_DIR, "agents", "node-enabled-agent");
|
|
200
|
+
mkdirSync(agentDir, {
|
|
201
|
+
recursive: true
|
|
202
|
+
});
|
|
203
|
+
const config = {
|
|
204
|
+
name: "node-enabled-agent",
|
|
205
|
+
description: "Agent with default node tools",
|
|
206
|
+
systemPrompt: "You are node capable"
|
|
207
|
+
};
|
|
208
|
+
writeFileSync(join(agentDir, "agent.json"), JSON.stringify(config));
|
|
209
|
+
const loader = new AgentLoader(TEST_CONFIG_DIR);
|
|
210
|
+
const agent = await loader.loadAgent("node-enabled-agent");
|
|
211
|
+
const toolNames = (agent?.tools || []).map((tool)=>tool.name);
|
|
212
|
+
expect(toolNames).toContain("node_notify");
|
|
213
|
+
expect(toolNames).toContain("node_run");
|
|
214
|
+
});
|
|
215
|
+
it("should always inject and deduplicate node tools for subagents", async ()=>{
|
|
216
|
+
const agentDir = join(TEST_CONFIG_DIR, "agents", "node-subagent-parent");
|
|
217
|
+
mkdirSync(agentDir, {
|
|
218
|
+
recursive: true
|
|
219
|
+
});
|
|
220
|
+
const config = {
|
|
221
|
+
name: "node-subagent-parent",
|
|
222
|
+
description: "Parent agent",
|
|
223
|
+
systemPrompt: "You are the parent",
|
|
224
|
+
subAgents: [
|
|
225
|
+
{
|
|
226
|
+
name: "node-subagent",
|
|
227
|
+
description: "Subagent",
|
|
228
|
+
systemPrompt: "You are a subagent",
|
|
229
|
+
tools: [
|
|
230
|
+
"node_run"
|
|
231
|
+
]
|
|
232
|
+
}
|
|
233
|
+
]
|
|
234
|
+
};
|
|
235
|
+
writeFileSync(join(agentDir, "agent.json"), JSON.stringify(config));
|
|
236
|
+
const loader = new AgentLoader(TEST_CONFIG_DIR);
|
|
237
|
+
const agent = await loader.loadAgent("node-subagent-parent");
|
|
238
|
+
const sub = agent?.subagents?.[0];
|
|
239
|
+
const toolNames = (sub?.tools || []).map((tool)=>tool.name);
|
|
240
|
+
expect(toolNames).toContain("node_notify");
|
|
241
|
+
expect(toolNames.filter((name)=>"node_run" === name)).toHaveLength(1);
|
|
242
|
+
});
|
|
198
243
|
it("should hydrate subagent tools for runtime use", async ()=>{
|
|
199
244
|
const agentDir = join(TEST_CONFIG_DIR, "agents", "parent-agent");
|
|
200
245
|
mkdirSync(agentDir, {
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
createNodeNotifyTool: ()=>createNodeNotifyTool,
|
|
28
|
+
createNodeRunTool: ()=>createNodeRunTool
|
|
29
|
+
});
|
|
30
|
+
const external_langchain_namespaceObject = require("langchain");
|
|
31
|
+
const external_zod_namespaceObject = require("zod");
|
|
32
|
+
const DEFAULT_NODE_TIMEOUT_MS = 30000;
|
|
33
|
+
const TargetSchema = external_zod_namespaceObject.object({
|
|
34
|
+
nodeId: external_zod_namespaceObject.string().min(1).optional(),
|
|
35
|
+
clientId: external_zod_namespaceObject.string().min(1).optional()
|
|
36
|
+
}).optional();
|
|
37
|
+
function resolveTarget(target, defaultTargetClientId) {
|
|
38
|
+
const targetNodeId = target?.nodeId?.trim();
|
|
39
|
+
if (targetNodeId) return {
|
|
40
|
+
targetNodeId
|
|
41
|
+
};
|
|
42
|
+
const targetClientId = target?.clientId?.trim() || defaultTargetClientId?.trim();
|
|
43
|
+
if (targetClientId) return {
|
|
44
|
+
targetClientId
|
|
45
|
+
};
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
48
|
+
function missingInvokerResult(toolName) {
|
|
49
|
+
return {
|
|
50
|
+
ok: false,
|
|
51
|
+
error: `${toolName} is only available when invoked through Wingman Gateway.`
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const createNodeNotifyTool = (options = {})=>{
|
|
55
|
+
const { nodeInvoker, defaultTargetClientId } = options;
|
|
56
|
+
return (0, external_langchain_namespaceObject.tool)(async ({ body, title, target, timeoutMs })=>{
|
|
57
|
+
if (!nodeInvoker) return missingInvokerResult("node_notify");
|
|
58
|
+
try {
|
|
59
|
+
const { targetNodeId, targetClientId } = resolveTarget(target, defaultTargetClientId);
|
|
60
|
+
const result = await nodeInvoker({
|
|
61
|
+
tool: "system.notify",
|
|
62
|
+
args: {
|
|
63
|
+
title: title?.trim() || "Wingman",
|
|
64
|
+
body: body.trim()
|
|
65
|
+
},
|
|
66
|
+
timeoutMs: timeoutMs ?? DEFAULT_NODE_TIMEOUT_MS,
|
|
67
|
+
targetNodeId,
|
|
68
|
+
targetClientId,
|
|
69
|
+
capability: "system.notify"
|
|
70
|
+
});
|
|
71
|
+
const payload = result.payload && "object" == typeof result.payload ? result.payload : null;
|
|
72
|
+
return {
|
|
73
|
+
ok: true,
|
|
74
|
+
nodeId: result.nodeId,
|
|
75
|
+
delivered: payload?.delivered === true,
|
|
76
|
+
payload: result.payload
|
|
77
|
+
};
|
|
78
|
+
} catch (error) {
|
|
79
|
+
return {
|
|
80
|
+
ok: false,
|
|
81
|
+
error: error instanceof Error ? error.message : String(error)
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}, {
|
|
85
|
+
name: "node_notify",
|
|
86
|
+
description: "Send a user-visible notification on an approved connected node device via system.notify.",
|
|
87
|
+
schema: external_zod_namespaceObject.object({
|
|
88
|
+
body: external_zod_namespaceObject.string().min(1).describe("Notification body text shown on the node device"),
|
|
89
|
+
title: external_zod_namespaceObject.string().min(1).optional().describe("Optional notification title"),
|
|
90
|
+
target: TargetSchema.describe("Optional target selector. Use nodeId for a specific node or clientId for a paired device."),
|
|
91
|
+
timeoutMs: external_zod_namespaceObject.number().int().min(1000).max(120000).optional().describe("Optional timeout for node execution in milliseconds")
|
|
92
|
+
})
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
const createNodeRunTool = (options = {})=>{
|
|
96
|
+
const { nodeInvoker, defaultTargetClientId } = options;
|
|
97
|
+
return (0, external_langchain_namespaceObject.tool)(async ({ command, args, target, timeoutMs })=>{
|
|
98
|
+
if (!nodeInvoker) return missingInvokerResult("node_run");
|
|
99
|
+
try {
|
|
100
|
+
const { targetNodeId, targetClientId } = resolveTarget(target, defaultTargetClientId);
|
|
101
|
+
const result = await nodeInvoker({
|
|
102
|
+
tool: "system.run",
|
|
103
|
+
args: {
|
|
104
|
+
command: command.trim(),
|
|
105
|
+
args: Array.isArray(args) ? args : []
|
|
106
|
+
},
|
|
107
|
+
timeoutMs: timeoutMs ?? DEFAULT_NODE_TIMEOUT_MS,
|
|
108
|
+
targetNodeId,
|
|
109
|
+
targetClientId,
|
|
110
|
+
capability: "system.run"
|
|
111
|
+
});
|
|
112
|
+
const payload = result.payload && "object" == typeof result.payload ? result.payload : null;
|
|
113
|
+
return {
|
|
114
|
+
ok: true,
|
|
115
|
+
nodeId: result.nodeId,
|
|
116
|
+
exitCode: "number" == typeof payload?.exitCode ? payload.exitCode : void 0,
|
|
117
|
+
stdout: "string" == typeof payload?.stdout ? payload.stdout : "",
|
|
118
|
+
stderr: "string" == typeof payload?.stderr ? payload.stderr : "",
|
|
119
|
+
payload: result.payload
|
|
120
|
+
};
|
|
121
|
+
} catch (error) {
|
|
122
|
+
return {
|
|
123
|
+
ok: false,
|
|
124
|
+
error: error instanceof Error ? error.message : String(error)
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}, {
|
|
128
|
+
name: "node_run",
|
|
129
|
+
description: "Run a command on an approved connected node device via system.run and return exitCode/stdout/stderr.",
|
|
130
|
+
schema: external_zod_namespaceObject.object({
|
|
131
|
+
command: external_zod_namespaceObject.string().min(1).describe("Executable command path/name to run on the node device"),
|
|
132
|
+
args: external_zod_namespaceObject.array(external_zod_namespaceObject.string()).optional().describe("Optional command arguments"),
|
|
133
|
+
target: TargetSchema.describe("Optional target selector. Use nodeId for a specific node or clientId for a paired device."),
|
|
134
|
+
timeoutMs: external_zod_namespaceObject.number().int().min(1000).max(120000).optional().describe("Optional timeout for node execution in milliseconds")
|
|
135
|
+
})
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
exports.createNodeNotifyTool = __webpack_exports__.createNodeNotifyTool;
|
|
139
|
+
exports.createNodeRunTool = __webpack_exports__.createNodeRunTool;
|
|
140
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
141
|
+
"createNodeNotifyTool",
|
|
142
|
+
"createNodeRunTool"
|
|
143
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
144
|
+
Object.defineProperty(exports, '__esModule', {
|
|
145
|
+
value: true
|
|
146
|
+
});
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
export type NodeInvokeRequest = {
|
|
3
|
+
tool: "system.notify" | "system.run";
|
|
4
|
+
args?: Record<string, unknown>;
|
|
5
|
+
timeoutMs?: number;
|
|
6
|
+
targetNodeId?: string;
|
|
7
|
+
targetClientId?: string;
|
|
8
|
+
capability?: string;
|
|
9
|
+
};
|
|
10
|
+
export type NodeInvokeResult = {
|
|
11
|
+
nodeId: string;
|
|
12
|
+
payload: unknown;
|
|
13
|
+
};
|
|
14
|
+
export type NodeInvoker = (request: NodeInvokeRequest) => Promise<NodeInvokeResult>;
|
|
15
|
+
export interface NodeToolOptions {
|
|
16
|
+
nodeInvoker?: NodeInvoker;
|
|
17
|
+
defaultTargetClientId?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare const createNodeNotifyTool: (options?: NodeToolOptions) => import("langchain").DynamicStructuredTool<z.ZodObject<{
|
|
20
|
+
body: z.ZodString;
|
|
21
|
+
title: z.ZodOptional<z.ZodString>;
|
|
22
|
+
target: z.ZodOptional<z.ZodObject<{
|
|
23
|
+
nodeId: z.ZodOptional<z.ZodString>;
|
|
24
|
+
clientId: z.ZodOptional<z.ZodString>;
|
|
25
|
+
}, z.core.$strip>>;
|
|
26
|
+
timeoutMs: z.ZodOptional<z.ZodNumber>;
|
|
27
|
+
}, z.core.$strip>, {
|
|
28
|
+
body: string;
|
|
29
|
+
title?: string;
|
|
30
|
+
target?: {
|
|
31
|
+
nodeId?: string;
|
|
32
|
+
clientId?: string;
|
|
33
|
+
};
|
|
34
|
+
timeoutMs?: number;
|
|
35
|
+
}, {
|
|
36
|
+
body: string;
|
|
37
|
+
title?: string | undefined;
|
|
38
|
+
target?: {
|
|
39
|
+
nodeId?: string | undefined;
|
|
40
|
+
clientId?: string | undefined;
|
|
41
|
+
} | undefined;
|
|
42
|
+
timeoutMs?: number | undefined;
|
|
43
|
+
}, {
|
|
44
|
+
ok: boolean;
|
|
45
|
+
error: string;
|
|
46
|
+
} | {
|
|
47
|
+
ok: boolean;
|
|
48
|
+
nodeId: string;
|
|
49
|
+
delivered: boolean;
|
|
50
|
+
payload: unknown;
|
|
51
|
+
}, "node_notify">;
|
|
52
|
+
export declare const createNodeRunTool: (options?: NodeToolOptions) => import("langchain").DynamicStructuredTool<z.ZodObject<{
|
|
53
|
+
command: z.ZodString;
|
|
54
|
+
args: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
55
|
+
target: z.ZodOptional<z.ZodObject<{
|
|
56
|
+
nodeId: z.ZodOptional<z.ZodString>;
|
|
57
|
+
clientId: z.ZodOptional<z.ZodString>;
|
|
58
|
+
}, z.core.$strip>>;
|
|
59
|
+
timeoutMs: z.ZodOptional<z.ZodNumber>;
|
|
60
|
+
}, z.core.$strip>, {
|
|
61
|
+
command: string;
|
|
62
|
+
args?: string[];
|
|
63
|
+
target?: {
|
|
64
|
+
nodeId?: string;
|
|
65
|
+
clientId?: string;
|
|
66
|
+
};
|
|
67
|
+
timeoutMs?: number;
|
|
68
|
+
}, {
|
|
69
|
+
command: string;
|
|
70
|
+
args?: string[] | undefined;
|
|
71
|
+
target?: {
|
|
72
|
+
nodeId?: string | undefined;
|
|
73
|
+
clientId?: string | undefined;
|
|
74
|
+
} | undefined;
|
|
75
|
+
timeoutMs?: number | undefined;
|
|
76
|
+
}, {
|
|
77
|
+
ok: boolean;
|
|
78
|
+
error: string;
|
|
79
|
+
} | {
|
|
80
|
+
ok: boolean;
|
|
81
|
+
nodeId: string;
|
|
82
|
+
exitCode: number | undefined;
|
|
83
|
+
stdout: string;
|
|
84
|
+
stderr: string;
|
|
85
|
+
payload: unknown;
|
|
86
|
+
}, "node_run">;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { tool } from "langchain";
|
|
2
|
+
import { array, number, object, string } from "zod";
|
|
3
|
+
const DEFAULT_NODE_TIMEOUT_MS = 30000;
|
|
4
|
+
const TargetSchema = object({
|
|
5
|
+
nodeId: string().min(1).optional(),
|
|
6
|
+
clientId: string().min(1).optional()
|
|
7
|
+
}).optional();
|
|
8
|
+
function resolveTarget(target, defaultTargetClientId) {
|
|
9
|
+
const targetNodeId = target?.nodeId?.trim();
|
|
10
|
+
if (targetNodeId) return {
|
|
11
|
+
targetNodeId
|
|
12
|
+
};
|
|
13
|
+
const targetClientId = target?.clientId?.trim() || defaultTargetClientId?.trim();
|
|
14
|
+
if (targetClientId) return {
|
|
15
|
+
targetClientId
|
|
16
|
+
};
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
function missingInvokerResult(toolName) {
|
|
20
|
+
return {
|
|
21
|
+
ok: false,
|
|
22
|
+
error: `${toolName} is only available when invoked through Wingman Gateway.`
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const createNodeNotifyTool = (options = {})=>{
|
|
26
|
+
const { nodeInvoker, defaultTargetClientId } = options;
|
|
27
|
+
return tool(async ({ body, title, target, timeoutMs })=>{
|
|
28
|
+
if (!nodeInvoker) return missingInvokerResult("node_notify");
|
|
29
|
+
try {
|
|
30
|
+
const { targetNodeId, targetClientId } = resolveTarget(target, defaultTargetClientId);
|
|
31
|
+
const result = await nodeInvoker({
|
|
32
|
+
tool: "system.notify",
|
|
33
|
+
args: {
|
|
34
|
+
title: title?.trim() || "Wingman",
|
|
35
|
+
body: body.trim()
|
|
36
|
+
},
|
|
37
|
+
timeoutMs: timeoutMs ?? DEFAULT_NODE_TIMEOUT_MS,
|
|
38
|
+
targetNodeId,
|
|
39
|
+
targetClientId,
|
|
40
|
+
capability: "system.notify"
|
|
41
|
+
});
|
|
42
|
+
const payload = result.payload && "object" == typeof result.payload ? result.payload : null;
|
|
43
|
+
return {
|
|
44
|
+
ok: true,
|
|
45
|
+
nodeId: result.nodeId,
|
|
46
|
+
delivered: payload?.delivered === true,
|
|
47
|
+
payload: result.payload
|
|
48
|
+
};
|
|
49
|
+
} catch (error) {
|
|
50
|
+
return {
|
|
51
|
+
ok: false,
|
|
52
|
+
error: error instanceof Error ? error.message : String(error)
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}, {
|
|
56
|
+
name: "node_notify",
|
|
57
|
+
description: "Send a user-visible notification on an approved connected node device via system.notify.",
|
|
58
|
+
schema: object({
|
|
59
|
+
body: string().min(1).describe("Notification body text shown on the node device"),
|
|
60
|
+
title: string().min(1).optional().describe("Optional notification title"),
|
|
61
|
+
target: TargetSchema.describe("Optional target selector. Use nodeId for a specific node or clientId for a paired device."),
|
|
62
|
+
timeoutMs: number().int().min(1000).max(120000).optional().describe("Optional timeout for node execution in milliseconds")
|
|
63
|
+
})
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
const createNodeRunTool = (options = {})=>{
|
|
67
|
+
const { nodeInvoker, defaultTargetClientId } = options;
|
|
68
|
+
return tool(async ({ command, args, target, timeoutMs })=>{
|
|
69
|
+
if (!nodeInvoker) return missingInvokerResult("node_run");
|
|
70
|
+
try {
|
|
71
|
+
const { targetNodeId, targetClientId } = resolveTarget(target, defaultTargetClientId);
|
|
72
|
+
const result = await nodeInvoker({
|
|
73
|
+
tool: "system.run",
|
|
74
|
+
args: {
|
|
75
|
+
command: command.trim(),
|
|
76
|
+
args: Array.isArray(args) ? args : []
|
|
77
|
+
},
|
|
78
|
+
timeoutMs: timeoutMs ?? DEFAULT_NODE_TIMEOUT_MS,
|
|
79
|
+
targetNodeId,
|
|
80
|
+
targetClientId,
|
|
81
|
+
capability: "system.run"
|
|
82
|
+
});
|
|
83
|
+
const payload = result.payload && "object" == typeof result.payload ? result.payload : null;
|
|
84
|
+
return {
|
|
85
|
+
ok: true,
|
|
86
|
+
nodeId: result.nodeId,
|
|
87
|
+
exitCode: "number" == typeof payload?.exitCode ? payload.exitCode : void 0,
|
|
88
|
+
stdout: "string" == typeof payload?.stdout ? payload.stdout : "",
|
|
89
|
+
stderr: "string" == typeof payload?.stderr ? payload.stderr : "",
|
|
90
|
+
payload: result.payload
|
|
91
|
+
};
|
|
92
|
+
} catch (error) {
|
|
93
|
+
return {
|
|
94
|
+
ok: false,
|
|
95
|
+
error: error instanceof Error ? error.message : String(error)
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}, {
|
|
99
|
+
name: "node_run",
|
|
100
|
+
description: "Run a command on an approved connected node device via system.run and return exitCode/stdout/stderr.",
|
|
101
|
+
schema: object({
|
|
102
|
+
command: string().min(1).describe("Executable command path/name to run on the node device"),
|
|
103
|
+
args: array(string()).optional().describe("Optional command arguments"),
|
|
104
|
+
target: TargetSchema.describe("Optional target selector. Use nodeId for a specific node or clientId for a paired device."),
|
|
105
|
+
timeoutMs: number().int().min(1000).max(120000).optional().describe("Optional timeout for node execution in milliseconds")
|
|
106
|
+
})
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
export { createNodeNotifyTool, createNodeRunTool };
|
|
@@ -600,7 +600,7 @@ Examples:
|
|
|
600
600
|
Deployment:
|
|
601
601
|
Local: Run on localhost or LAN
|
|
602
602
|
Tailscale: Accessible over Tailscale network
|
|
603
|
-
Cloudflare: Deploy to Cloudflare Workers (see cloudflare/README.md)
|
|
603
|
+
Cloudflare: Deploy to Cloudflare Workers (see apps/cloudflare/README.md)
|
|
604
604
|
`);
|
|
605
605
|
}
|
|
606
606
|
exports.executeGatewayCommand = __webpack_exports__.executeGatewayCommand;
|
|
@@ -572,7 +572,7 @@ Examples:
|
|
|
572
572
|
Deployment:
|
|
573
573
|
Local: Run on localhost or LAN
|
|
574
574
|
Tailscale: Accessible over Tailscale network
|
|
575
|
-
Cloudflare: Deploy to Cloudflare Workers (see cloudflare/README.md)
|
|
575
|
+
Cloudflare: Deploy to Cloudflare Workers (see apps/cloudflare/README.md)
|
|
576
576
|
`);
|
|
577
577
|
}
|
|
578
578
|
export { executeGatewayCommand };
|