@wingman-ai/gateway 0.4.2 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/dist/agent/config/mcpClientManager.cjs +104 -1
- package/dist/agent/config/mcpClientManager.d.ts +30 -0
- package/dist/agent/config/mcpClientManager.js +104 -1
- package/dist/agent/config/modelFactory.cjs +10 -0
- package/dist/agent/config/modelFactory.js +10 -0
- package/dist/agent/config/xaiImageModel.cjs +242 -0
- package/dist/agent/config/xaiImageModel.d.ts +33 -0
- package/dist/agent/config/xaiImageModel.js +202 -0
- package/dist/agent/tests/mcpClientManager.test.cjs +116 -0
- package/dist/agent/tests/mcpClientManager.test.js +117 -1
- package/dist/agent/tests/mcpResourceTools.test.cjs +101 -0
- package/dist/agent/tests/mcpResourceTools.test.d.ts +1 -0
- package/dist/agent/tests/mcpResourceTools.test.js +95 -0
- package/dist/agent/tests/modelFactory.test.cjs +16 -2
- package/dist/agent/tests/modelFactory.test.js +16 -2
- package/dist/agent/tests/xaiImageModel.test.cjs +194 -0
- package/dist/agent/tests/xaiImageModel.test.d.ts +1 -0
- package/dist/agent/tests/xaiImageModel.test.js +188 -0
- package/dist/agent/tools/mcp_resources.cjs +111 -0
- package/dist/agent/tools/mcp_resources.d.ts +3 -0
- package/dist/agent/tools/mcp_resources.js +77 -0
- package/dist/bench/adapters/commandAdapter.cjs +93 -0
- package/dist/bench/adapters/commandAdapter.d.ts +6 -0
- package/dist/bench/adapters/commandAdapter.js +59 -0
- package/dist/bench/adapters/helpers.cjs +170 -0
- package/dist/bench/adapters/helpers.d.ts +7 -0
- package/dist/bench/adapters/helpers.js +133 -0
- package/dist/bench/adapters/index.cjs +41 -0
- package/dist/bench/adapters/index.d.ts +2 -0
- package/dist/bench/adapters/index.js +7 -0
- package/dist/bench/adapters/wingmanCliAdapter.cjs +100 -0
- package/dist/bench/adapters/wingmanCliAdapter.d.ts +6 -0
- package/dist/bench/adapters/wingmanCliAdapter.js +66 -0
- package/dist/bench/cleanup.cjs +122 -0
- package/dist/bench/cleanup.d.ts +9 -0
- package/dist/bench/cleanup.js +85 -0
- package/dist/bench/config.cjs +190 -0
- package/dist/bench/config.d.ts +2 -0
- package/dist/bench/config.js +156 -0
- package/dist/bench/index.cjs +43 -0
- package/dist/bench/index.d.ts +3 -0
- package/dist/bench/index.js +3 -0
- package/dist/bench/official.cjs +616 -0
- package/dist/bench/official.d.ts +80 -0
- package/dist/bench/official.js +546 -0
- package/dist/bench/officialCli.cjs +204 -0
- package/dist/bench/officialCli.d.ts +5 -0
- package/dist/bench/officialCli.js +170 -0
- package/dist/bench/process.cjs +78 -0
- package/dist/bench/process.d.ts +14 -0
- package/dist/bench/process.js +44 -0
- package/dist/bench/runner.cjs +237 -0
- package/dist/bench/runner.d.ts +7 -0
- package/dist/bench/runner.js +197 -0
- package/dist/bench/scoring.cjs +171 -0
- package/dist/bench/scoring.d.ts +9 -0
- package/dist/bench/scoring.js +137 -0
- package/dist/bench/types.cjs +18 -0
- package/dist/bench/types.d.ts +200 -0
- package/dist/bench/types.js +0 -0
- package/dist/bench/validator.cjs +92 -0
- package/dist/bench/validator.d.ts +2 -0
- package/dist/bench/validator.js +58 -0
- package/dist/cli/config/schema.cjs +36 -1
- package/dist/cli/config/schema.d.ts +46 -0
- package/dist/cli/config/schema.js +36 -1
- package/dist/cli/config/warnings.cjs +119 -51
- package/dist/cli/config/warnings.js +119 -51
- package/dist/cli/core/agentInvoker.cjs +9 -2
- package/dist/cli/core/agentInvoker.d.ts +1 -0
- package/dist/cli/core/agentInvoker.js +9 -2
- package/dist/cli/core/imagePersistence.cjs +17 -1
- package/dist/cli/core/imagePersistence.d.ts +2 -0
- package/dist/cli/core/imagePersistence.js +13 -3
- package/dist/cli/core/sessionManager.cjs +2 -0
- package/dist/cli/core/sessionManager.js +3 -1
- package/dist/cli/types.d.ts +18 -0
- package/dist/gateway/adapters/teams.cjs +419 -0
- package/dist/gateway/adapters/teams.d.ts +47 -0
- package/dist/gateway/adapters/teams.js +361 -0
- package/dist/gateway/http/sms.cjs +286 -0
- package/dist/gateway/http/sms.d.ts +4 -0
- package/dist/gateway/http/sms.js +249 -0
- package/dist/gateway/server.cjs +54 -3
- package/dist/gateway/server.d.ts +2 -0
- package/dist/gateway/server.js +54 -3
- package/dist/gateway/sms/commands.cjs +116 -0
- package/dist/gateway/sms/commands.d.ts +15 -0
- package/dist/gateway/sms/commands.js +79 -0
- package/dist/gateway/sms/control.cjs +118 -0
- package/dist/gateway/sms/control.d.ts +18 -0
- package/dist/gateway/sms/control.js +84 -0
- package/dist/gateway/sms/policyStore.cjs +198 -0
- package/dist/gateway/sms/policyStore.d.ts +37 -0
- package/dist/gateway/sms/policyStore.js +161 -0
- package/dist/providers/registry.cjs +1 -0
- package/dist/providers/registry.js +1 -0
- package/dist/tests/cli-config-warnings.test.cjs +41 -0
- package/dist/tests/cli-config-warnings.test.js +41 -0
- package/dist/tests/cli-init.test.cjs +32 -26
- package/dist/tests/cli-init.test.js +32 -26
- package/dist/tests/gateway-http-security.test.cjs +21 -0
- package/dist/tests/gateway-http-security.test.js +21 -0
- package/dist/tests/gateway-origin-policy.test.cjs +22 -0
- package/dist/tests/gateway-origin-policy.test.js +22 -0
- package/dist/tests/gateway.test.cjs +57 -0
- package/dist/tests/gateway.test.js +57 -0
- package/dist/tests/imagePersistence.test.cjs +26 -0
- package/dist/tests/imagePersistence.test.js +27 -1
- package/dist/tests/run-terminal-bench-official-script.test.cjs +61 -0
- package/dist/tests/run-terminal-bench-official-script.test.d.ts +1 -0
- package/dist/tests/run-terminal-bench-official-script.test.js +55 -0
- package/dist/tests/sessions-api.test.cjs +69 -1
- package/dist/tests/sessions-api.test.js +70 -2
- package/dist/tests/sms-api.test.cjs +183 -0
- package/dist/tests/sms-api.test.d.ts +1 -0
- package/dist/tests/sms-api.test.js +177 -0
- package/dist/tests/sms-commands.test.cjs +90 -0
- package/dist/tests/sms-commands.test.d.ts +1 -0
- package/dist/tests/sms-commands.test.js +84 -0
- package/dist/tests/sms-policy-store.test.cjs +69 -0
- package/dist/tests/sms-policy-store.test.d.ts +1 -0
- package/dist/tests/sms-policy-store.test.js +63 -0
- package/dist/tests/teams-adapter.test.cjs +58 -0
- package/dist/tests/teams-adapter.test.d.ts +1 -0
- package/dist/tests/teams-adapter.test.js +52 -0
- package/dist/tests/terminal-bench-adapters-helpers.test.cjs +64 -0
- package/dist/tests/terminal-bench-adapters-helpers.test.d.ts +1 -0
- package/dist/tests/terminal-bench-adapters-helpers.test.js +58 -0
- package/dist/tests/terminal-bench-cleanup.test.cjs +93 -0
- package/dist/tests/terminal-bench-cleanup.test.d.ts +1 -0
- package/dist/tests/terminal-bench-cleanup.test.js +87 -0
- package/dist/tests/terminal-bench-config.test.cjs +62 -0
- package/dist/tests/terminal-bench-config.test.d.ts +1 -0
- package/dist/tests/terminal-bench-config.test.js +56 -0
- package/dist/tests/terminal-bench-official.test.cjs +194 -0
- package/dist/tests/terminal-bench-official.test.d.ts +1 -0
- package/dist/tests/terminal-bench-official.test.js +188 -0
- package/dist/tests/terminal-bench-runner.test.cjs +82 -0
- package/dist/tests/terminal-bench-runner.test.d.ts +1 -0
- package/dist/tests/terminal-bench-runner.test.js +76 -0
- package/dist/tests/terminal-bench-scoring.test.cjs +128 -0
- package/dist/tests/terminal-bench-scoring.test.d.ts +1 -0
- package/dist/tests/terminal-bench-scoring.test.js +122 -0
- package/dist/tools/mcp-fal-ai.cjs +1 -1
- package/dist/tools/mcp-fal-ai.js +1 -1
- package/dist/webui/assets/index-Cyg_Hs57.css +11 -0
- package/dist/webui/assets/{index-BMekSELC.js → index-DZXLLjaA.js} +109 -109
- package/dist/webui/index.html +2 -2
- package/package.json +11 -2
- package/templates/agents/game-dev/agent.md +122 -63
- package/templates/agents/game-dev/art-director.md +106 -0
- package/templates/agents/game-dev/game-designer.md +87 -0
- package/templates/agents/game-dev/scene-engineer.md +474 -0
- package/dist/webui/assets/index-Cwkg4DKj.css +0 -11
- package/templates/agents/game-dev/art-generation.md +0 -38
- package/templates/agents/game-dev/asset-refinement.md +0 -17
- package/templates/agents/game-dev/planning-idea.md +0 -17
- package/templates/agents/game-dev/ui-specialist.md +0 -17
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
const MAX_TARGET_LENGTH = 256;
|
|
4
|
+
const MINUTE_LIMIT = 1439;
|
|
5
|
+
function isAlertMode(value) {
|
|
6
|
+
return "off" === value || "important-only" === value || "all" === value;
|
|
7
|
+
}
|
|
8
|
+
function normalizeQuietHours(value) {
|
|
9
|
+
if (!value || "object" != typeof value || Array.isArray(value)) return null;
|
|
10
|
+
const candidate = value;
|
|
11
|
+
const startMinute = "number" == typeof candidate.startMinute ? candidate.startMinute : NaN;
|
|
12
|
+
const endMinute = "number" == typeof candidate.endMinute ? candidate.endMinute : NaN;
|
|
13
|
+
if (!Number.isInteger(startMinute) || startMinute < 0 || startMinute > MINUTE_LIMIT || !Number.isInteger(endMinute) || endMinute < 0 || endMinute > MINUTE_LIMIT) return null;
|
|
14
|
+
return {
|
|
15
|
+
enabled: false !== candidate.enabled,
|
|
16
|
+
startMinute,
|
|
17
|
+
endMinute,
|
|
18
|
+
timezone: "string" == typeof candidate.timezone && candidate.timezone.trim() ? candidate.timezone.trim() : void 0
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function normalizeTarget(raw) {
|
|
22
|
+
const trimmed = raw.trim();
|
|
23
|
+
if (!trimmed || trimmed.length > MAX_TARGET_LENGTH) return null;
|
|
24
|
+
return trimmed;
|
|
25
|
+
}
|
|
26
|
+
function normalizeSmsPolicyTarget(raw) {
|
|
27
|
+
return normalizeTarget(raw);
|
|
28
|
+
}
|
|
29
|
+
function createDefaultPolicy(target, nowMs) {
|
|
30
|
+
return {
|
|
31
|
+
target,
|
|
32
|
+
paused: false,
|
|
33
|
+
pausedUntil: null,
|
|
34
|
+
stopEnabled: false,
|
|
35
|
+
alertMode: "important-only",
|
|
36
|
+
quietHours: null,
|
|
37
|
+
createdAt: nowMs,
|
|
38
|
+
updatedAt: nowMs
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function parsePolicyRecord(entry) {
|
|
42
|
+
if (!entry || "object" != typeof entry || Array.isArray(entry)) return null;
|
|
43
|
+
const typed = entry;
|
|
44
|
+
const target = "string" == typeof typed.target ? normalizeTarget(typed.target) : null;
|
|
45
|
+
if (!target) return null;
|
|
46
|
+
const createdAt = "number" == typeof typed.createdAt && Number.isFinite(typed.createdAt) ? typed.createdAt : Date.now();
|
|
47
|
+
const updatedAt = "number" == typeof typed.updatedAt && Number.isFinite(typed.updatedAt) ? typed.updatedAt : createdAt;
|
|
48
|
+
const paused = true === typed.paused;
|
|
49
|
+
const pausedUntil = "number" == typeof typed.pausedUntil && Number.isFinite(typed.pausedUntil) ? Math.trunc(typed.pausedUntil) : null;
|
|
50
|
+
return {
|
|
51
|
+
target,
|
|
52
|
+
paused,
|
|
53
|
+
pausedUntil: paused ? pausedUntil : null,
|
|
54
|
+
stopEnabled: true === typed.stopEnabled,
|
|
55
|
+
alertMode: isAlertMode(typed.alertMode) ? typed.alertMode : "important-only",
|
|
56
|
+
quietHours: normalizeQuietHours(typed.quietHours),
|
|
57
|
+
createdAt,
|
|
58
|
+
updatedAt
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function resolveExpiredPause(record, nowMs) {
|
|
62
|
+
if (!record.paused || null === record.pausedUntil || record.pausedUntil > nowMs) return record;
|
|
63
|
+
return {
|
|
64
|
+
...record,
|
|
65
|
+
paused: false,
|
|
66
|
+
pausedUntil: null,
|
|
67
|
+
updatedAt: nowMs
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const createSmsPolicyStore = (resolveConfigDirPath)=>{
|
|
71
|
+
const resolvePath = ()=>{
|
|
72
|
+
const configDir = resolveConfigDirPath();
|
|
73
|
+
mkdirSync(configDir, {
|
|
74
|
+
recursive: true
|
|
75
|
+
});
|
|
76
|
+
return join(configDir, "sms-policies.json");
|
|
77
|
+
};
|
|
78
|
+
const readRecords = ()=>{
|
|
79
|
+
const path = resolvePath();
|
|
80
|
+
if (!existsSync(path)) return [];
|
|
81
|
+
try {
|
|
82
|
+
const raw = readFileSync(path, "utf-8");
|
|
83
|
+
const parsed = JSON.parse(raw);
|
|
84
|
+
if (!Array.isArray(parsed)) return [];
|
|
85
|
+
const records = [];
|
|
86
|
+
for (const entry of parsed){
|
|
87
|
+
const record = parsePolicyRecord(entry);
|
|
88
|
+
if (record) records.push(record);
|
|
89
|
+
}
|
|
90
|
+
return records;
|
|
91
|
+
} catch {
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const writeRecords = (records)=>{
|
|
96
|
+
const path = resolvePath();
|
|
97
|
+
writeFileSync(path, JSON.stringify(records, null, 2));
|
|
98
|
+
};
|
|
99
|
+
const replaceRecord = (records, nextRecord)=>{
|
|
100
|
+
const index = records.findIndex((record)=>record.target === nextRecord.target);
|
|
101
|
+
if (index >= 0) records[index] = nextRecord;
|
|
102
|
+
else records.unshift(nextRecord);
|
|
103
|
+
return records;
|
|
104
|
+
};
|
|
105
|
+
const resolveRecord = (target, nowMs = Date.now())=>{
|
|
106
|
+
const normalizedTarget = normalizeTarget(target);
|
|
107
|
+
if (!normalizedTarget) return createDefaultPolicy("unknown", nowMs);
|
|
108
|
+
const records = readRecords();
|
|
109
|
+
const existing = records.find((record)=>record.target === normalizedTarget);
|
|
110
|
+
if (!existing) return createDefaultPolicy(normalizedTarget, nowMs);
|
|
111
|
+
const resolved = resolveExpiredPause(existing, nowMs);
|
|
112
|
+
if (resolved !== existing) writeRecords(replaceRecord(records, resolved));
|
|
113
|
+
return resolved;
|
|
114
|
+
};
|
|
115
|
+
return {
|
|
116
|
+
load: ()=>readRecords(),
|
|
117
|
+
save: (records)=>writeRecords(records),
|
|
118
|
+
list: ()=>readRecords(),
|
|
119
|
+
get: (target)=>{
|
|
120
|
+
const normalizedTarget = normalizeTarget(target);
|
|
121
|
+
if (!normalizedTarget) return null;
|
|
122
|
+
return readRecords().find((record)=>record.target === normalizedTarget) || null;
|
|
123
|
+
},
|
|
124
|
+
resolve: (target, nowMs = Date.now())=>resolveRecord(target, nowMs),
|
|
125
|
+
upsert: (target, patch, nowMs = Date.now())=>{
|
|
126
|
+
const normalizedTarget = normalizeTarget(target);
|
|
127
|
+
if (!normalizedTarget) throw new Error("Invalid SMS policy target");
|
|
128
|
+
const records = readRecords();
|
|
129
|
+
const existing = records.find((record)=>record.target === normalizedTarget);
|
|
130
|
+
const base = existing || createDefaultPolicy(normalizedTarget, nowMs);
|
|
131
|
+
const next = {
|
|
132
|
+
...base,
|
|
133
|
+
updatedAt: nowMs
|
|
134
|
+
};
|
|
135
|
+
if ("boolean" == typeof patch.paused) next.paused = patch.paused;
|
|
136
|
+
if (Object.hasOwn(patch, "pausedUntil")) {
|
|
137
|
+
const value = patch.pausedUntil;
|
|
138
|
+
if ("number" == typeof value && Number.isFinite(value)) next.pausedUntil = Math.trunc(value);
|
|
139
|
+
else next.pausedUntil = null;
|
|
140
|
+
}
|
|
141
|
+
if ("boolean" == typeof patch.stopEnabled) next.stopEnabled = patch.stopEnabled;
|
|
142
|
+
if (isAlertMode(patch.alertMode)) next.alertMode = patch.alertMode;
|
|
143
|
+
if (Object.hasOwn(patch, "quietHours")) next.quietHours = patch.quietHours ? normalizeQuietHours(patch.quietHours) : null;
|
|
144
|
+
if (!next.paused) next.pausedUntil = null;
|
|
145
|
+
const resolved = resolveExpiredPause(next, nowMs);
|
|
146
|
+
writeRecords(replaceRecord(records, resolved));
|
|
147
|
+
return resolved;
|
|
148
|
+
},
|
|
149
|
+
reset: (target)=>{
|
|
150
|
+
const normalizedTarget = normalizeTarget(target);
|
|
151
|
+
if (!normalizedTarget) return;
|
|
152
|
+
const records = readRecords();
|
|
153
|
+
const filtered = records.filter((record)=>record.target !== normalizedTarget);
|
|
154
|
+
if (filtered.length === records.length) return;
|
|
155
|
+
writeRecords(filtered);
|
|
156
|
+
},
|
|
157
|
+
isPaused: (target, nowMs = Date.now())=>resolveRecord(target, nowMs).paused,
|
|
158
|
+
isStopped: (target, nowMs = Date.now())=>resolveRecord(target, nowMs).stopEnabled
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
export { createSmsPolicyStore, normalizeSmsPolicyTarget };
|
|
@@ -42,6 +42,47 @@ const warnings_cjs_namespaceObject = require("../cli/config/warnings.cjs");
|
|
|
42
42
|
(0, external_vitest_namespaceObject.expect)(warnings.some((msg)=>msg.includes("allowedChannels"))).toBe(true);
|
|
43
43
|
(0, external_vitest_namespaceObject.expect)(warnings.some((msg)=>msg.includes("allowedGuilds"))).toBe(true);
|
|
44
44
|
});
|
|
45
|
+
(0, external_vitest_namespaceObject.it)("returns warnings for common Teams config issues", ()=>{
|
|
46
|
+
const base = (0, schema_cjs_namespaceObject.validateConfig)({}).data;
|
|
47
|
+
const config = (0, schema_cjs_namespaceObject.validateConfig)({
|
|
48
|
+
...base,
|
|
49
|
+
gateway: {
|
|
50
|
+
...base.gateway,
|
|
51
|
+
adapters: {
|
|
52
|
+
...base.gateway.adapters,
|
|
53
|
+
teams: {
|
|
54
|
+
enabled: true,
|
|
55
|
+
appId: "",
|
|
56
|
+
appPassword: " ",
|
|
57
|
+
appType: "MultiTenant",
|
|
58
|
+
endpointPath: " ",
|
|
59
|
+
mentionOnly: true,
|
|
60
|
+
allowBots: false,
|
|
61
|
+
allowedTeamIds: [
|
|
62
|
+
" "
|
|
63
|
+
],
|
|
64
|
+
allowedChannelIds: [
|
|
65
|
+
"",
|
|
66
|
+
" 19:abc "
|
|
67
|
+
],
|
|
68
|
+
channelSessions: {
|
|
69
|
+
" 19:channel ": " session-plain "
|
|
70
|
+
},
|
|
71
|
+
sessionCommand: " ",
|
|
72
|
+
responseChunkSize: 3500
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}).data;
|
|
77
|
+
const warnings = (0, warnings_cjs_namespaceObject.collectConfigWarnings)(config).map((warning)=>warning.message);
|
|
78
|
+
(0, external_vitest_namespaceObject.expect)(warnings.some((msg)=>msg.includes("appId/appPassword"))).toBe(true);
|
|
79
|
+
(0, external_vitest_namespaceObject.expect)(warnings.some((msg)=>msg.includes("sessionCommand"))).toBe(true);
|
|
80
|
+
(0, external_vitest_namespaceObject.expect)(warnings.some((msg)=>msg.includes("endpointPath"))).toBe(true);
|
|
81
|
+
(0, external_vitest_namespaceObject.expect)(warnings.some((msg)=>msg.includes("channelSessions"))).toBe(true);
|
|
82
|
+
(0, external_vitest_namespaceObject.expect)(warnings.some((msg)=>msg.includes("agent prefix"))).toBe(true);
|
|
83
|
+
(0, external_vitest_namespaceObject.expect)(warnings.some((msg)=>msg.includes("allowedChannelIds"))).toBe(true);
|
|
84
|
+
(0, external_vitest_namespaceObject.expect)(warnings.some((msg)=>msg.includes("allowedTeamIds"))).toBe(true);
|
|
85
|
+
});
|
|
45
86
|
(0, external_vitest_namespaceObject.it)("returns no warnings when Discord adapter is disabled", ()=>{
|
|
46
87
|
const base = (0, schema_cjs_namespaceObject.validateConfig)({}).data;
|
|
47
88
|
(0, external_vitest_namespaceObject.expect)((0, warnings_cjs_namespaceObject.collectConfigWarnings)(base)).toEqual([]);
|
|
@@ -40,6 +40,47 @@ describe("Config warnings", ()=>{
|
|
|
40
40
|
expect(warnings.some((msg)=>msg.includes("allowedChannels"))).toBe(true);
|
|
41
41
|
expect(warnings.some((msg)=>msg.includes("allowedGuilds"))).toBe(true);
|
|
42
42
|
});
|
|
43
|
+
it("returns warnings for common Teams config issues", ()=>{
|
|
44
|
+
const base = validateConfig({}).data;
|
|
45
|
+
const config = validateConfig({
|
|
46
|
+
...base,
|
|
47
|
+
gateway: {
|
|
48
|
+
...base.gateway,
|
|
49
|
+
adapters: {
|
|
50
|
+
...base.gateway.adapters,
|
|
51
|
+
teams: {
|
|
52
|
+
enabled: true,
|
|
53
|
+
appId: "",
|
|
54
|
+
appPassword: " ",
|
|
55
|
+
appType: "MultiTenant",
|
|
56
|
+
endpointPath: " ",
|
|
57
|
+
mentionOnly: true,
|
|
58
|
+
allowBots: false,
|
|
59
|
+
allowedTeamIds: [
|
|
60
|
+
" "
|
|
61
|
+
],
|
|
62
|
+
allowedChannelIds: [
|
|
63
|
+
"",
|
|
64
|
+
" 19:abc "
|
|
65
|
+
],
|
|
66
|
+
channelSessions: {
|
|
67
|
+
" 19:channel ": " session-plain "
|
|
68
|
+
},
|
|
69
|
+
sessionCommand: " ",
|
|
70
|
+
responseChunkSize: 3500
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}).data;
|
|
75
|
+
const warnings = collectConfigWarnings(config).map((warning)=>warning.message);
|
|
76
|
+
expect(warnings.some((msg)=>msg.includes("appId/appPassword"))).toBe(true);
|
|
77
|
+
expect(warnings.some((msg)=>msg.includes("sessionCommand"))).toBe(true);
|
|
78
|
+
expect(warnings.some((msg)=>msg.includes("endpointPath"))).toBe(true);
|
|
79
|
+
expect(warnings.some((msg)=>msg.includes("channelSessions"))).toBe(true);
|
|
80
|
+
expect(warnings.some((msg)=>msg.includes("agent prefix"))).toBe(true);
|
|
81
|
+
expect(warnings.some((msg)=>msg.includes("allowedChannelIds"))).toBe(true);
|
|
82
|
+
expect(warnings.some((msg)=>msg.includes("allowedTeamIds"))).toBe(true);
|
|
83
|
+
});
|
|
43
84
|
it("returns no warnings when Discord adapter is disabled", ()=>{
|
|
44
85
|
const base = validateConfig({}).data;
|
|
45
86
|
expect(collectConfigWarnings(base)).toEqual([]);
|
|
@@ -77,35 +77,41 @@ const init_cjs_namespaceObject = require("../cli/commands/init.cjs");
|
|
|
77
77
|
const gameDevPrompt = (0, external_node_fs_namespaceObject.readFileSync)(gameDevAgentPath, "utf-8");
|
|
78
78
|
(0, external_vitest_namespaceObject.expect)(gameDevPrompt).toContain("name: game-dev");
|
|
79
79
|
(0, external_vitest_namespaceObject.expect)(gameDevPrompt).toContain("subAgents:");
|
|
80
|
-
(0, external_vitest_namespaceObject.expect)(gameDevPrompt).toContain("name: art-
|
|
81
|
-
(0, external_vitest_namespaceObject.expect)(gameDevPrompt).toContain("promptFile: ./art-
|
|
82
|
-
(0, external_vitest_namespaceObject.expect)(gameDevPrompt).toContain("name:
|
|
83
|
-
(0, external_vitest_namespaceObject.expect)(gameDevPrompt).toContain("promptFile: ./
|
|
84
|
-
(0, external_vitest_namespaceObject.expect)(gameDevPrompt).toContain("name:
|
|
85
|
-
(0, external_vitest_namespaceObject.expect)(gameDevPrompt).toContain("promptFile: ./
|
|
86
|
-
(0, external_vitest_namespaceObject.expect)(gameDevPrompt).toContain("name: ui-specialist");
|
|
87
|
-
(0, external_vitest_namespaceObject.expect)(gameDevPrompt).toContain("promptFile: ./ui-specialist.md");
|
|
80
|
+
(0, external_vitest_namespaceObject.expect)(gameDevPrompt).toContain("name: art-director");
|
|
81
|
+
(0, external_vitest_namespaceObject.expect)(gameDevPrompt).toContain("promptFile: ./art-director.md");
|
|
82
|
+
(0, external_vitest_namespaceObject.expect)(gameDevPrompt).toContain("name: scene-engineer");
|
|
83
|
+
(0, external_vitest_namespaceObject.expect)(gameDevPrompt).toContain("promptFile: ./scene-engineer.md");
|
|
84
|
+
(0, external_vitest_namespaceObject.expect)(gameDevPrompt).toContain("name: game-designer");
|
|
85
|
+
(0, external_vitest_namespaceObject.expect)(gameDevPrompt).toContain("promptFile: ./game-designer.md");
|
|
88
86
|
(0, external_vitest_namespaceObject.expect)(gameDevPrompt).toContain("write_todos");
|
|
89
87
|
(0, external_vitest_namespaceObject.expect)(gameDevPrompt).toContain("read_todos");
|
|
90
|
-
(0, external_vitest_namespaceObject.expect)(gameDevPrompt).toContain("
|
|
88
|
+
(0, external_vitest_namespaceObject.expect)(gameDevPrompt).toContain("Delegation routing");
|
|
91
89
|
(0, external_vitest_namespaceObject.expect)(gameDevPrompt).toContain("MeshStandardMaterial");
|
|
92
|
-
(0, external_vitest_namespaceObject.expect)(gameDevPrompt).toContain("
|
|
93
|
-
const
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
(0, external_vitest_namespaceObject.expect)((0, external_node_fs_namespaceObject.existsSync)(
|
|
98
|
-
(0, external_vitest_namespaceObject.expect)((0, external_node_fs_namespaceObject.existsSync)(
|
|
99
|
-
(0,
|
|
100
|
-
(0, external_vitest_namespaceObject.expect)(
|
|
101
|
-
|
|
102
|
-
(0, external_vitest_namespaceObject.expect)(
|
|
103
|
-
(0, external_vitest_namespaceObject.expect)(
|
|
104
|
-
(0,
|
|
105
|
-
(0, external_vitest_namespaceObject.expect)(
|
|
106
|
-
(0, external_vitest_namespaceObject.expect)(
|
|
107
|
-
(0, external_vitest_namespaceObject.expect)(
|
|
108
|
-
(0,
|
|
90
|
+
(0, external_vitest_namespaceObject.expect)(gameDevPrompt).toContain("three-mesh-bvh");
|
|
91
|
+
const gameDevArtDirectorPath = (0, external_node_path_namespaceObject.join)(workspace, ".wingman", "agents", "game-dev", "art-director.md");
|
|
92
|
+
const gameDevSceneEngineerPath = (0, external_node_path_namespaceObject.join)(workspace, ".wingman", "agents", "game-dev", "scene-engineer.md");
|
|
93
|
+
const gameDevDesignerPath = (0, external_node_path_namespaceObject.join)(workspace, ".wingman", "agents", "game-dev", "game-designer.md");
|
|
94
|
+
(0, external_vitest_namespaceObject.expect)((0, external_node_fs_namespaceObject.existsSync)(gameDevArtDirectorPath)).toBe(true);
|
|
95
|
+
(0, external_vitest_namespaceObject.expect)((0, external_node_fs_namespaceObject.existsSync)(gameDevSceneEngineerPath)).toBe(true);
|
|
96
|
+
(0, external_vitest_namespaceObject.expect)((0, external_node_fs_namespaceObject.existsSync)(gameDevDesignerPath)).toBe(true);
|
|
97
|
+
const gameDevArtDirectorPrompt = (0, external_node_fs_namespaceObject.readFileSync)(gameDevArtDirectorPath, "utf-8");
|
|
98
|
+
(0, external_vitest_namespaceObject.expect)(gameDevArtDirectorPrompt).toContain("You are `art-director`");
|
|
99
|
+
(0, external_vitest_namespaceObject.expect)(gameDevArtDirectorPrompt).toContain("Texture-to-geometry mapping: mesh, material slot, UV set");
|
|
100
|
+
(0, external_vitest_namespaceObject.expect)(gameDevArtDirectorPrompt).toContain("flipY = false");
|
|
101
|
+
(0, external_vitest_namespaceObject.expect)(gameDevArtDirectorPrompt).toContain("RepeatWrapping");
|
|
102
|
+
const gameDevSceneEngineerPrompt = (0, external_node_fs_namespaceObject.readFileSync)(gameDevSceneEngineerPath, "utf-8");
|
|
103
|
+
(0, external_vitest_namespaceObject.expect)(gameDevSceneEngineerPrompt).toContain("You are `scene-engineer`");
|
|
104
|
+
(0, external_vitest_namespaceObject.expect)(gameDevSceneEngineerPrompt).toContain("Rapier is the default physics engine");
|
|
105
|
+
(0, external_vitest_namespaceObject.expect)(gameDevSceneEngineerPrompt).toContain("Prefer `postprocessing` over Three.js built-in `EffectComposer`");
|
|
106
|
+
const gameDevDesignerPrompt = (0, external_node_fs_namespaceObject.readFileSync)(gameDevDesignerPath, "utf-8");
|
|
107
|
+
(0, external_vitest_namespaceObject.expect)(gameDevDesignerPrompt).toContain("You are `game-designer`");
|
|
108
|
+
(0, external_vitest_namespaceObject.expect)(gameDevDesignerPrompt).toContain("Always present 2-3 mechanic variants with tradeoffs");
|
|
109
|
+
(0, external_vitest_namespaceObject.expect)(gameDevDesignerPrompt).toContain("UI Conventions");
|
|
110
|
+
const mainAgentTemplatePath = (0, external_node_path_namespaceObject.join)(workspace, ".wingman", "agents", "main", "agent.md");
|
|
111
|
+
(0, external_vitest_namespaceObject.expect)((0, external_node_fs_namespaceObject.existsSync)(mainAgentTemplatePath)).toBe(true);
|
|
112
|
+
const mainAgentTemplatePrompt = (0, external_node_fs_namespaceObject.readFileSync)(mainAgentTemplatePath, "utf-8");
|
|
113
|
+
(0, external_vitest_namespaceObject.expect)(mainAgentTemplatePrompt).toContain("name: main");
|
|
114
|
+
(0, external_vitest_namespaceObject.expect)(mainAgentTemplatePrompt).toContain("Primary Wingman agent");
|
|
109
115
|
});
|
|
110
116
|
(0, external_vitest_namespaceObject.it)("merges existing config when --merge is set", async ()=>{
|
|
111
117
|
const configDir = (0, external_node_path_namespaceObject.join)(workspace, ".wingman");
|
|
@@ -75,35 +75,41 @@ describe("CLI init", ()=>{
|
|
|
75
75
|
const gameDevPrompt = readFileSync(gameDevAgentPath, "utf-8");
|
|
76
76
|
expect(gameDevPrompt).toContain("name: game-dev");
|
|
77
77
|
expect(gameDevPrompt).toContain("subAgents:");
|
|
78
|
-
expect(gameDevPrompt).toContain("name: art-
|
|
79
|
-
expect(gameDevPrompt).toContain("promptFile: ./art-
|
|
80
|
-
expect(gameDevPrompt).toContain("name:
|
|
81
|
-
expect(gameDevPrompt).toContain("promptFile: ./
|
|
82
|
-
expect(gameDevPrompt).toContain("name:
|
|
83
|
-
expect(gameDevPrompt).toContain("promptFile: ./
|
|
84
|
-
expect(gameDevPrompt).toContain("name: ui-specialist");
|
|
85
|
-
expect(gameDevPrompt).toContain("promptFile: ./ui-specialist.md");
|
|
78
|
+
expect(gameDevPrompt).toContain("name: art-director");
|
|
79
|
+
expect(gameDevPrompt).toContain("promptFile: ./art-director.md");
|
|
80
|
+
expect(gameDevPrompt).toContain("name: scene-engineer");
|
|
81
|
+
expect(gameDevPrompt).toContain("promptFile: ./scene-engineer.md");
|
|
82
|
+
expect(gameDevPrompt).toContain("name: game-designer");
|
|
83
|
+
expect(gameDevPrompt).toContain("promptFile: ./game-designer.md");
|
|
86
84
|
expect(gameDevPrompt).toContain("write_todos");
|
|
87
85
|
expect(gameDevPrompt).toContain("read_todos");
|
|
88
|
-
expect(gameDevPrompt).toContain("
|
|
86
|
+
expect(gameDevPrompt).toContain("Delegation routing");
|
|
89
87
|
expect(gameDevPrompt).toContain("MeshStandardMaterial");
|
|
90
|
-
expect(gameDevPrompt).toContain("
|
|
91
|
-
const
|
|
92
|
-
const
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
expect(existsSync(
|
|
96
|
-
expect(existsSync(
|
|
97
|
-
|
|
98
|
-
expect(
|
|
99
|
-
|
|
100
|
-
expect(
|
|
101
|
-
expect(
|
|
102
|
-
|
|
103
|
-
expect(
|
|
104
|
-
expect(
|
|
105
|
-
expect(
|
|
106
|
-
|
|
88
|
+
expect(gameDevPrompt).toContain("three-mesh-bvh");
|
|
89
|
+
const gameDevArtDirectorPath = join(workspace, ".wingman", "agents", "game-dev", "art-director.md");
|
|
90
|
+
const gameDevSceneEngineerPath = join(workspace, ".wingman", "agents", "game-dev", "scene-engineer.md");
|
|
91
|
+
const gameDevDesignerPath = join(workspace, ".wingman", "agents", "game-dev", "game-designer.md");
|
|
92
|
+
expect(existsSync(gameDevArtDirectorPath)).toBe(true);
|
|
93
|
+
expect(existsSync(gameDevSceneEngineerPath)).toBe(true);
|
|
94
|
+
expect(existsSync(gameDevDesignerPath)).toBe(true);
|
|
95
|
+
const gameDevArtDirectorPrompt = readFileSync(gameDevArtDirectorPath, "utf-8");
|
|
96
|
+
expect(gameDevArtDirectorPrompt).toContain("You are `art-director`");
|
|
97
|
+
expect(gameDevArtDirectorPrompt).toContain("Texture-to-geometry mapping: mesh, material slot, UV set");
|
|
98
|
+
expect(gameDevArtDirectorPrompt).toContain("flipY = false");
|
|
99
|
+
expect(gameDevArtDirectorPrompt).toContain("RepeatWrapping");
|
|
100
|
+
const gameDevSceneEngineerPrompt = readFileSync(gameDevSceneEngineerPath, "utf-8");
|
|
101
|
+
expect(gameDevSceneEngineerPrompt).toContain("You are `scene-engineer`");
|
|
102
|
+
expect(gameDevSceneEngineerPrompt).toContain("Rapier is the default physics engine");
|
|
103
|
+
expect(gameDevSceneEngineerPrompt).toContain("Prefer `postprocessing` over Three.js built-in `EffectComposer`");
|
|
104
|
+
const gameDevDesignerPrompt = readFileSync(gameDevDesignerPath, "utf-8");
|
|
105
|
+
expect(gameDevDesignerPrompt).toContain("You are `game-designer`");
|
|
106
|
+
expect(gameDevDesignerPrompt).toContain("Always present 2-3 mechanic variants with tradeoffs");
|
|
107
|
+
expect(gameDevDesignerPrompt).toContain("UI Conventions");
|
|
108
|
+
const mainAgentTemplatePath = join(workspace, ".wingman", "agents", "main", "agent.md");
|
|
109
|
+
expect(existsSync(mainAgentTemplatePath)).toBe(true);
|
|
110
|
+
const mainAgentTemplatePrompt = readFileSync(mainAgentTemplatePath, "utf-8");
|
|
111
|
+
expect(mainAgentTemplatePrompt).toContain("name: main");
|
|
112
|
+
expect(mainAgentTemplatePrompt).toContain("Primary Wingman agent");
|
|
107
113
|
});
|
|
108
114
|
it("merges existing config when --merge is set", async ()=>{
|
|
109
115
|
const configDir = join(workspace, ".wingman");
|
|
@@ -93,6 +93,27 @@ function createTestSocket(initialData) {
|
|
|
93
93
|
(0, external_vitest_namespaceObject.expect)(allowed.status).toBe(204);
|
|
94
94
|
(0, external_vitest_namespaceObject.expect)(allowed.headers.get("access-control-allow-origin")).toBe("http://localhost:5173");
|
|
95
95
|
});
|
|
96
|
+
(0, external_vitest_namespaceObject.it)("allows tauri loopback origin preflight for desktop clients", async ()=>{
|
|
97
|
+
const server = createGateway({
|
|
98
|
+
host: "127.0.0.1",
|
|
99
|
+
port: 18789,
|
|
100
|
+
auth: {
|
|
101
|
+
mode: "token",
|
|
102
|
+
token: "test-token"
|
|
103
|
+
},
|
|
104
|
+
requireAuth: true
|
|
105
|
+
});
|
|
106
|
+
const internals = getGatewayInternals(server);
|
|
107
|
+
const allowed = await internals.handleUiRequest(new Request("http://127.0.0.1:18789/api/providers", {
|
|
108
|
+
method: "OPTIONS",
|
|
109
|
+
headers: {
|
|
110
|
+
Origin: "tauri://localhost",
|
|
111
|
+
"Access-Control-Request-Method": "GET"
|
|
112
|
+
}
|
|
113
|
+
}));
|
|
114
|
+
(0, external_vitest_namespaceObject.expect)(allowed.status).toBe(204);
|
|
115
|
+
(0, external_vitest_namespaceObject.expect)(allowed.headers.get("access-control-allow-origin")).toBe("tauri://localhost");
|
|
116
|
+
});
|
|
96
117
|
(0, external_vitest_namespaceObject.it)("does not trust tailscale identity headers on non-loopback hosts", ()=>{
|
|
97
118
|
const server = createGateway({
|
|
98
119
|
host: "0.0.0.0",
|
|
@@ -91,6 +91,27 @@ describe("gateway HTTP security", ()=>{
|
|
|
91
91
|
expect(allowed.status).toBe(204);
|
|
92
92
|
expect(allowed.headers.get("access-control-allow-origin")).toBe("http://localhost:5173");
|
|
93
93
|
});
|
|
94
|
+
it("allows tauri loopback origin preflight for desktop clients", async ()=>{
|
|
95
|
+
const server = createGateway({
|
|
96
|
+
host: "127.0.0.1",
|
|
97
|
+
port: 18789,
|
|
98
|
+
auth: {
|
|
99
|
+
mode: "token",
|
|
100
|
+
token: "test-token"
|
|
101
|
+
},
|
|
102
|
+
requireAuth: true
|
|
103
|
+
});
|
|
104
|
+
const internals = getGatewayInternals(server);
|
|
105
|
+
const allowed = await internals.handleUiRequest(new Request("http://127.0.0.1:18789/api/providers", {
|
|
106
|
+
method: "OPTIONS",
|
|
107
|
+
headers: {
|
|
108
|
+
Origin: "tauri://localhost",
|
|
109
|
+
"Access-Control-Request-Method": "GET"
|
|
110
|
+
}
|
|
111
|
+
}));
|
|
112
|
+
expect(allowed.status).toBe(204);
|
|
113
|
+
expect(allowed.headers.get("access-control-allow-origin")).toBe("tauri://localhost");
|
|
114
|
+
});
|
|
94
115
|
it("does not trust tailscale identity headers on non-loopback hosts", ()=>{
|
|
95
116
|
const server = createGateway({
|
|
96
117
|
host: "0.0.0.0",
|
|
@@ -20,6 +20,17 @@ const server_cjs_namespaceObject = require("../gateway/server.cjs");
|
|
|
20
20
|
});
|
|
21
21
|
(0, external_vitest_namespaceObject.expect)(allowed).toBe(true);
|
|
22
22
|
});
|
|
23
|
+
(0, external_vitest_namespaceObject.it)("allows tauri loopback origins for desktop clients", ()=>{
|
|
24
|
+
const allowed = (0, server_cjs_namespaceObject.isGatewayOriginAllowed)({
|
|
25
|
+
origin: "tauri://localhost",
|
|
26
|
+
requestUrl: "http://127.0.0.1:18789/api/sessions",
|
|
27
|
+
gatewayHost: "127.0.0.1",
|
|
28
|
+
gatewayPort: 18789,
|
|
29
|
+
controlUiEnabled: true,
|
|
30
|
+
controlUiPort: 18790
|
|
31
|
+
});
|
|
32
|
+
(0, external_vitest_namespaceObject.expect)(allowed).toBe(true);
|
|
33
|
+
});
|
|
23
34
|
(0, external_vitest_namespaceObject.it)("rejects unrelated internet origins", ()=>{
|
|
24
35
|
const allowed = (0, server_cjs_namespaceObject.isGatewayOriginAllowed)({
|
|
25
36
|
origin: "https://evil.example",
|
|
@@ -53,6 +64,17 @@ const server_cjs_namespaceObject = require("../gateway/server.cjs");
|
|
|
53
64
|
});
|
|
54
65
|
(0, external_vitest_namespaceObject.expect)(allowed).toBe(false);
|
|
55
66
|
});
|
|
67
|
+
(0, external_vitest_namespaceObject.it)("rejects tauri origins for non-loopback gateways", ()=>{
|
|
68
|
+
const allowed = (0, server_cjs_namespaceObject.isGatewayOriginAllowed)({
|
|
69
|
+
origin: "tauri://localhost",
|
|
70
|
+
requestUrl: "http://192.168.1.50:18789/api/sessions",
|
|
71
|
+
gatewayHost: "0.0.0.0",
|
|
72
|
+
gatewayPort: 18789,
|
|
73
|
+
controlUiEnabled: true,
|
|
74
|
+
controlUiPort: 18790
|
|
75
|
+
});
|
|
76
|
+
(0, external_vitest_namespaceObject.expect)(allowed).toBe(false);
|
|
77
|
+
});
|
|
56
78
|
});
|
|
57
79
|
for(var __rspack_i in __webpack_exports__)exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
58
80
|
Object.defineProperty(exports, '__esModule', {
|
|
@@ -18,6 +18,17 @@ describe("gateway origin policy", ()=>{
|
|
|
18
18
|
});
|
|
19
19
|
expect(allowed).toBe(true);
|
|
20
20
|
});
|
|
21
|
+
it("allows tauri loopback origins for desktop clients", ()=>{
|
|
22
|
+
const allowed = isGatewayOriginAllowed({
|
|
23
|
+
origin: "tauri://localhost",
|
|
24
|
+
requestUrl: "http://127.0.0.1:18789/api/sessions",
|
|
25
|
+
gatewayHost: "127.0.0.1",
|
|
26
|
+
gatewayPort: 18789,
|
|
27
|
+
controlUiEnabled: true,
|
|
28
|
+
controlUiPort: 18790
|
|
29
|
+
});
|
|
30
|
+
expect(allowed).toBe(true);
|
|
31
|
+
});
|
|
21
32
|
it("rejects unrelated internet origins", ()=>{
|
|
22
33
|
const allowed = isGatewayOriginAllowed({
|
|
23
34
|
origin: "https://evil.example",
|
|
@@ -51,4 +62,15 @@ describe("gateway origin policy", ()=>{
|
|
|
51
62
|
});
|
|
52
63
|
expect(allowed).toBe(false);
|
|
53
64
|
});
|
|
65
|
+
it("rejects tauri origins for non-loopback gateways", ()=>{
|
|
66
|
+
const allowed = isGatewayOriginAllowed({
|
|
67
|
+
origin: "tauri://localhost",
|
|
68
|
+
requestUrl: "http://192.168.1.50:18789/api/sessions",
|
|
69
|
+
gatewayHost: "0.0.0.0",
|
|
70
|
+
gatewayPort: 18789,
|
|
71
|
+
controlUiEnabled: true,
|
|
72
|
+
controlUiPort: 18790
|
|
73
|
+
});
|
|
74
|
+
expect(allowed).toBe(false);
|
|
75
|
+
});
|
|
54
76
|
});
|
|
@@ -22,6 +22,40 @@ external_vitest_namespaceObject.vi.mock("@/cli/core/agentInvoker.js", ()=>({
|
|
|
22
22
|
AgentInvoker: class {
|
|
23
23
|
async invokeAgent(_agentId, content, _sessionId, _attachments, options) {
|
|
24
24
|
if ("throw-no-event" === content) throw new Error("Synthetic invocation failure");
|
|
25
|
+
if ("stream-model-failure-no-error" === content) {
|
|
26
|
+
this.outputManager?.emitAgentStream?.({
|
|
27
|
+
event: "on_chain_end",
|
|
28
|
+
run_id: "model-failure-run-1",
|
|
29
|
+
name: "ChannelWrite<branch:to:todoListMiddleware.after_model>",
|
|
30
|
+
data: {
|
|
31
|
+
output: [
|
|
32
|
+
{
|
|
33
|
+
lg_name: "Command",
|
|
34
|
+
update: {
|
|
35
|
+
messages: [
|
|
36
|
+
{
|
|
37
|
+
type: "constructor",
|
|
38
|
+
id: [
|
|
39
|
+
"langchain_core",
|
|
40
|
+
"messages",
|
|
41
|
+
"AIMessage"
|
|
42
|
+
],
|
|
43
|
+
kwargs: {
|
|
44
|
+
id: "model-failure-msg-1",
|
|
45
|
+
content: "Model call failed after 3 attempts with Error: xAI image generation failed: Prompt len is larger than the maximum allowed length which is 8000"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
input: {}
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
return {
|
|
56
|
+
streaming: true
|
|
57
|
+
};
|
|
58
|
+
}
|
|
25
59
|
const signal = options?.signal;
|
|
26
60
|
await new Promise((resolve)=>{
|
|
27
61
|
const timer = setTimeout(resolve, 75);
|
|
@@ -412,6 +446,29 @@ describeIfBun("Gateway", ()=>{
|
|
|
412
446
|
});
|
|
413
447
|
requester.close();
|
|
414
448
|
});
|
|
449
|
+
(0, external_vitest_namespaceObject.it)("does not auto-convert streamed model failure text into agent-error", async ()=>{
|
|
450
|
+
const requester = await connectClient("session-streamed-failure-requester");
|
|
451
|
+
const requestId = "req-streamed-failure-no-error";
|
|
452
|
+
const sessionId = "session-streamed-failure-no-error";
|
|
453
|
+
requester.send(JSON.stringify({
|
|
454
|
+
type: "req:agent",
|
|
455
|
+
id: requestId,
|
|
456
|
+
payload: {
|
|
457
|
+
agentId: "main",
|
|
458
|
+
sessionKey: sessionId,
|
|
459
|
+
content: "stream-model-failure-no-error"
|
|
460
|
+
},
|
|
461
|
+
timestamp: Date.now()
|
|
462
|
+
}));
|
|
463
|
+
const streamMsg = await waitForMessage(requester, (msg)=>"event:agent" === msg.type && msg.id === requestId && msg.payload?.type === "agent-stream" && msg.payload?.chunk?.event === "on_chain_end", 10000);
|
|
464
|
+
(0, external_vitest_namespaceObject.expect)(JSON.stringify(streamMsg.payload?.chunk?.data || {})).toContain("Model call failed after 3 attempts");
|
|
465
|
+
const completeMsg = await waitForMessage(requester, (msg)=>"event:agent" === msg.type && msg.id === requestId && msg.payload?.type === "agent-complete", 10000);
|
|
466
|
+
(0, external_vitest_namespaceObject.expect)(completeMsg.payload?.sessionId).toBe(sessionId);
|
|
467
|
+
(0, external_vitest_namespaceObject.expect)(completeMsg.payload?.agentId).toBe("main");
|
|
468
|
+
const terminalErrorEvents = await collectMessages(requester, (msg)=>"event:agent" === msg.type && msg.id === requestId && msg.payload?.type === "agent-error", 400);
|
|
469
|
+
(0, external_vitest_namespaceObject.expect)(terminalErrorEvents).toHaveLength(0);
|
|
470
|
+
requester.close();
|
|
471
|
+
});
|
|
415
472
|
(0, external_vitest_namespaceObject.it)("should emit a single agent-complete terminal event per request", async ()=>{
|
|
416
473
|
const requester = await connectClient("session-single-complete-requester");
|
|
417
474
|
const requestId = "req-single-complete";
|