@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.
Files changed (160) hide show
  1. package/README.md +14 -0
  2. package/dist/agent/config/mcpClientManager.cjs +104 -1
  3. package/dist/agent/config/mcpClientManager.d.ts +30 -0
  4. package/dist/agent/config/mcpClientManager.js +104 -1
  5. package/dist/agent/config/modelFactory.cjs +10 -0
  6. package/dist/agent/config/modelFactory.js +10 -0
  7. package/dist/agent/config/xaiImageModel.cjs +242 -0
  8. package/dist/agent/config/xaiImageModel.d.ts +33 -0
  9. package/dist/agent/config/xaiImageModel.js +202 -0
  10. package/dist/agent/tests/mcpClientManager.test.cjs +116 -0
  11. package/dist/agent/tests/mcpClientManager.test.js +117 -1
  12. package/dist/agent/tests/mcpResourceTools.test.cjs +101 -0
  13. package/dist/agent/tests/mcpResourceTools.test.d.ts +1 -0
  14. package/dist/agent/tests/mcpResourceTools.test.js +95 -0
  15. package/dist/agent/tests/modelFactory.test.cjs +16 -2
  16. package/dist/agent/tests/modelFactory.test.js +16 -2
  17. package/dist/agent/tests/xaiImageModel.test.cjs +194 -0
  18. package/dist/agent/tests/xaiImageModel.test.d.ts +1 -0
  19. package/dist/agent/tests/xaiImageModel.test.js +188 -0
  20. package/dist/agent/tools/mcp_resources.cjs +111 -0
  21. package/dist/agent/tools/mcp_resources.d.ts +3 -0
  22. package/dist/agent/tools/mcp_resources.js +77 -0
  23. package/dist/bench/adapters/commandAdapter.cjs +93 -0
  24. package/dist/bench/adapters/commandAdapter.d.ts +6 -0
  25. package/dist/bench/adapters/commandAdapter.js +59 -0
  26. package/dist/bench/adapters/helpers.cjs +170 -0
  27. package/dist/bench/adapters/helpers.d.ts +7 -0
  28. package/dist/bench/adapters/helpers.js +133 -0
  29. package/dist/bench/adapters/index.cjs +41 -0
  30. package/dist/bench/adapters/index.d.ts +2 -0
  31. package/dist/bench/adapters/index.js +7 -0
  32. package/dist/bench/adapters/wingmanCliAdapter.cjs +100 -0
  33. package/dist/bench/adapters/wingmanCliAdapter.d.ts +6 -0
  34. package/dist/bench/adapters/wingmanCliAdapter.js +66 -0
  35. package/dist/bench/cleanup.cjs +122 -0
  36. package/dist/bench/cleanup.d.ts +9 -0
  37. package/dist/bench/cleanup.js +85 -0
  38. package/dist/bench/config.cjs +190 -0
  39. package/dist/bench/config.d.ts +2 -0
  40. package/dist/bench/config.js +156 -0
  41. package/dist/bench/index.cjs +43 -0
  42. package/dist/bench/index.d.ts +3 -0
  43. package/dist/bench/index.js +3 -0
  44. package/dist/bench/official.cjs +616 -0
  45. package/dist/bench/official.d.ts +80 -0
  46. package/dist/bench/official.js +546 -0
  47. package/dist/bench/officialCli.cjs +204 -0
  48. package/dist/bench/officialCli.d.ts +5 -0
  49. package/dist/bench/officialCli.js +170 -0
  50. package/dist/bench/process.cjs +78 -0
  51. package/dist/bench/process.d.ts +14 -0
  52. package/dist/bench/process.js +44 -0
  53. package/dist/bench/runner.cjs +237 -0
  54. package/dist/bench/runner.d.ts +7 -0
  55. package/dist/bench/runner.js +197 -0
  56. package/dist/bench/scoring.cjs +171 -0
  57. package/dist/bench/scoring.d.ts +9 -0
  58. package/dist/bench/scoring.js +137 -0
  59. package/dist/bench/types.cjs +18 -0
  60. package/dist/bench/types.d.ts +200 -0
  61. package/dist/bench/types.js +0 -0
  62. package/dist/bench/validator.cjs +92 -0
  63. package/dist/bench/validator.d.ts +2 -0
  64. package/dist/bench/validator.js +58 -0
  65. package/dist/cli/config/schema.cjs +36 -1
  66. package/dist/cli/config/schema.d.ts +46 -0
  67. package/dist/cli/config/schema.js +36 -1
  68. package/dist/cli/config/warnings.cjs +119 -51
  69. package/dist/cli/config/warnings.js +119 -51
  70. package/dist/cli/core/agentInvoker.cjs +9 -2
  71. package/dist/cli/core/agentInvoker.d.ts +1 -0
  72. package/dist/cli/core/agentInvoker.js +9 -2
  73. package/dist/cli/core/imagePersistence.cjs +17 -1
  74. package/dist/cli/core/imagePersistence.d.ts +2 -0
  75. package/dist/cli/core/imagePersistence.js +13 -3
  76. package/dist/cli/core/sessionManager.cjs +2 -0
  77. package/dist/cli/core/sessionManager.js +3 -1
  78. package/dist/cli/types.d.ts +18 -0
  79. package/dist/gateway/adapters/teams.cjs +419 -0
  80. package/dist/gateway/adapters/teams.d.ts +47 -0
  81. package/dist/gateway/adapters/teams.js +361 -0
  82. package/dist/gateway/http/sms.cjs +286 -0
  83. package/dist/gateway/http/sms.d.ts +4 -0
  84. package/dist/gateway/http/sms.js +249 -0
  85. package/dist/gateway/server.cjs +54 -3
  86. package/dist/gateway/server.d.ts +2 -0
  87. package/dist/gateway/server.js +54 -3
  88. package/dist/gateway/sms/commands.cjs +116 -0
  89. package/dist/gateway/sms/commands.d.ts +15 -0
  90. package/dist/gateway/sms/commands.js +79 -0
  91. package/dist/gateway/sms/control.cjs +118 -0
  92. package/dist/gateway/sms/control.d.ts +18 -0
  93. package/dist/gateway/sms/control.js +84 -0
  94. package/dist/gateway/sms/policyStore.cjs +198 -0
  95. package/dist/gateway/sms/policyStore.d.ts +37 -0
  96. package/dist/gateway/sms/policyStore.js +161 -0
  97. package/dist/providers/registry.cjs +1 -0
  98. package/dist/providers/registry.js +1 -0
  99. package/dist/tests/cli-config-warnings.test.cjs +41 -0
  100. package/dist/tests/cli-config-warnings.test.js +41 -0
  101. package/dist/tests/cli-init.test.cjs +32 -26
  102. package/dist/tests/cli-init.test.js +32 -26
  103. package/dist/tests/gateway-http-security.test.cjs +21 -0
  104. package/dist/tests/gateway-http-security.test.js +21 -0
  105. package/dist/tests/gateway-origin-policy.test.cjs +22 -0
  106. package/dist/tests/gateway-origin-policy.test.js +22 -0
  107. package/dist/tests/gateway.test.cjs +57 -0
  108. package/dist/tests/gateway.test.js +57 -0
  109. package/dist/tests/imagePersistence.test.cjs +26 -0
  110. package/dist/tests/imagePersistence.test.js +27 -1
  111. package/dist/tests/run-terminal-bench-official-script.test.cjs +61 -0
  112. package/dist/tests/run-terminal-bench-official-script.test.d.ts +1 -0
  113. package/dist/tests/run-terminal-bench-official-script.test.js +55 -0
  114. package/dist/tests/sessions-api.test.cjs +69 -1
  115. package/dist/tests/sessions-api.test.js +70 -2
  116. package/dist/tests/sms-api.test.cjs +183 -0
  117. package/dist/tests/sms-api.test.d.ts +1 -0
  118. package/dist/tests/sms-api.test.js +177 -0
  119. package/dist/tests/sms-commands.test.cjs +90 -0
  120. package/dist/tests/sms-commands.test.d.ts +1 -0
  121. package/dist/tests/sms-commands.test.js +84 -0
  122. package/dist/tests/sms-policy-store.test.cjs +69 -0
  123. package/dist/tests/sms-policy-store.test.d.ts +1 -0
  124. package/dist/tests/sms-policy-store.test.js +63 -0
  125. package/dist/tests/teams-adapter.test.cjs +58 -0
  126. package/dist/tests/teams-adapter.test.d.ts +1 -0
  127. package/dist/tests/teams-adapter.test.js +52 -0
  128. package/dist/tests/terminal-bench-adapters-helpers.test.cjs +64 -0
  129. package/dist/tests/terminal-bench-adapters-helpers.test.d.ts +1 -0
  130. package/dist/tests/terminal-bench-adapters-helpers.test.js +58 -0
  131. package/dist/tests/terminal-bench-cleanup.test.cjs +93 -0
  132. package/dist/tests/terminal-bench-cleanup.test.d.ts +1 -0
  133. package/dist/tests/terminal-bench-cleanup.test.js +87 -0
  134. package/dist/tests/terminal-bench-config.test.cjs +62 -0
  135. package/dist/tests/terminal-bench-config.test.d.ts +1 -0
  136. package/dist/tests/terminal-bench-config.test.js +56 -0
  137. package/dist/tests/terminal-bench-official.test.cjs +194 -0
  138. package/dist/tests/terminal-bench-official.test.d.ts +1 -0
  139. package/dist/tests/terminal-bench-official.test.js +188 -0
  140. package/dist/tests/terminal-bench-runner.test.cjs +82 -0
  141. package/dist/tests/terminal-bench-runner.test.d.ts +1 -0
  142. package/dist/tests/terminal-bench-runner.test.js +76 -0
  143. package/dist/tests/terminal-bench-scoring.test.cjs +128 -0
  144. package/dist/tests/terminal-bench-scoring.test.d.ts +1 -0
  145. package/dist/tests/terminal-bench-scoring.test.js +122 -0
  146. package/dist/tools/mcp-fal-ai.cjs +1 -1
  147. package/dist/tools/mcp-fal-ai.js +1 -1
  148. package/dist/webui/assets/index-Cyg_Hs57.css +11 -0
  149. package/dist/webui/assets/{index-BMekSELC.js → index-DZXLLjaA.js} +109 -109
  150. package/dist/webui/index.html +2 -2
  151. package/package.json +11 -2
  152. package/templates/agents/game-dev/agent.md +122 -63
  153. package/templates/agents/game-dev/art-director.md +106 -0
  154. package/templates/agents/game-dev/game-designer.md +87 -0
  155. package/templates/agents/game-dev/scene-engineer.md +474 -0
  156. package/dist/webui/assets/index-Cwkg4DKj.css +0 -11
  157. package/templates/agents/game-dev/art-generation.md +0 -38
  158. package/templates/agents/game-dev/asset-refinement.md +0 -17
  159. package/templates/agents/game-dev/planning-idea.md +0 -17
  160. package/templates/agents/game-dev/ui-specialist.md +0 -17
@@ -32,66 +32,134 @@ const isBlank = (value)=>0 === value.trim().length;
32
32
  function collectConfigWarnings(config) {
33
33
  const warnings = [];
34
34
  const discord = config.gateway?.adapters?.discord;
35
- if (!discord?.enabled) return warnings;
36
- if (!discord.token) warnings.push({
37
- code: "discord-token-missing",
38
- message: "gateway.adapters.discord.enabled is true but gateway.adapters.discord.token is not set; the adapter will not start."
39
- });
40
- if (isBlank(discord.sessionCommand || "")) warnings.push({
41
- code: "discord-session-command-blank",
42
- message: 'gateway.adapters.discord.sessionCommand is blank; it will fall back to "!session".'
43
- });
44
- for (const [rawKey, rawValue] of Object.entries(discord.channelSessions ?? {})){
45
- const keyLabel = JSON.stringify(rawKey);
46
- const value = "string" == typeof rawValue ? rawValue : "";
47
- const valueLabel = JSON.stringify(value);
48
- if (hasLeadingOrTrailingWhitespace(rawKey)) warnings.push({
49
- code: "discord-channel-sessions-key-whitespace",
50
- message: `gateway.adapters.discord.channelSessions key ${keyLabel} has leading/trailing whitespace.`
35
+ const teams = config.gateway?.adapters?.teams;
36
+ if (discord?.enabled) {
37
+ if (!discord.token) warnings.push({
38
+ code: "discord-token-missing",
39
+ message: "gateway.adapters.discord.enabled is true but gateway.adapters.discord.token is not set; the adapter will not start."
51
40
  });
52
- if (hasLeadingOrTrailingWhitespace(value)) warnings.push({
53
- code: "discord-channel-sessions-value-whitespace",
54
- message: `gateway.adapters.discord.channelSessions[${keyLabel}] value ${valueLabel} has leading/trailing whitespace.`
41
+ if (isBlank(discord.sessionCommand || "")) warnings.push({
42
+ code: "discord-session-command-blank",
43
+ message: 'gateway.adapters.discord.sessionCommand is blank; it will fall back to "!session".'
55
44
  });
56
- if (isBlank(value)) {
57
- warnings.push({
58
- code: "discord-channel-sessions-value-blank",
59
- message: `gateway.adapters.discord.channelSessions[${keyLabel}] is empty; mapping will fall back to derived session keys.`
45
+ for (const [rawKey, rawValue] of Object.entries(discord.channelSessions ?? {})){
46
+ const keyLabel = JSON.stringify(rawKey);
47
+ const value = "string" == typeof rawValue ? rawValue : "";
48
+ const valueLabel = JSON.stringify(value);
49
+ if (hasLeadingOrTrailingWhitespace(rawKey)) warnings.push({
50
+ code: "discord-channel-sessions-key-whitespace",
51
+ message: `gateway.adapters.discord.channelSessions key ${keyLabel} has leading/trailing whitespace.`
52
+ });
53
+ if (hasLeadingOrTrailingWhitespace(value)) warnings.push({
54
+ code: "discord-channel-sessions-value-whitespace",
55
+ message: `gateway.adapters.discord.channelSessions[${keyLabel}] value ${valueLabel} has leading/trailing whitespace.`
56
+ });
57
+ if (isBlank(value)) {
58
+ warnings.push({
59
+ code: "discord-channel-sessions-value-blank",
60
+ message: `gateway.adapters.discord.channelSessions[${keyLabel}] is empty; mapping will fall back to derived session keys.`
61
+ });
62
+ continue;
63
+ }
64
+ if (!AGENT_PREFIX.test(value.trim())) warnings.push({
65
+ code: "discord-channel-sessions-missing-agent",
66
+ message: `gateway.adapters.discord.channelSessions[${keyLabel}] does not include an agent prefix (agent:<id>:...); agent selection will use bindings/default.`
60
67
  });
61
- continue;
62
68
  }
63
- if (!AGENT_PREFIX.test(value.trim())) warnings.push({
64
- code: "discord-channel-sessions-missing-agent",
65
- message: `gateway.adapters.discord.channelSessions[${keyLabel}] does not include an agent prefix (agent:<id>:...); agent selection will use bindings/default.`
66
- });
67
- }
68
- for (const entry of discord.allowedChannels ?? []){
69
- const label = JSON.stringify(entry);
70
- if (isBlank(entry)) {
71
- warnings.push({
72
- code: "discord-allowed-channels-blank",
73
- message: "gateway.adapters.discord.allowedChannels contains a blank entry; remove empty strings."
69
+ for (const entry of discord.allowedChannels ?? []){
70
+ const label = JSON.stringify(entry);
71
+ if (isBlank(entry)) {
72
+ warnings.push({
73
+ code: "discord-allowed-channels-blank",
74
+ message: "gateway.adapters.discord.allowedChannels contains a blank entry; remove empty strings."
75
+ });
76
+ continue;
77
+ }
78
+ if (hasLeadingOrTrailingWhitespace(entry)) warnings.push({
79
+ code: "discord-allowed-channels-whitespace",
80
+ message: `gateway.adapters.discord.allowedChannels contains ${label} with leading/trailing whitespace.`
74
81
  });
75
- continue;
76
82
  }
77
- if (hasLeadingOrTrailingWhitespace(entry)) warnings.push({
78
- code: "discord-allowed-channels-whitespace",
79
- message: `gateway.adapters.discord.allowedChannels contains ${label} with leading/trailing whitespace.`
80
- });
81
- }
82
- for (const entry of discord.allowedGuilds ?? []){
83
- const label = JSON.stringify(entry);
84
- if (isBlank(entry)) {
85
- warnings.push({
86
- code: "discord-allowed-guilds-blank",
87
- message: "gateway.adapters.discord.allowedGuilds contains a blank entry; remove empty strings."
83
+ for (const entry of discord.allowedGuilds ?? []){
84
+ const label = JSON.stringify(entry);
85
+ if (isBlank(entry)) {
86
+ warnings.push({
87
+ code: "discord-allowed-guilds-blank",
88
+ message: "gateway.adapters.discord.allowedGuilds contains a blank entry; remove empty strings."
89
+ });
90
+ continue;
91
+ }
92
+ if (hasLeadingOrTrailingWhitespace(entry)) warnings.push({
93
+ code: "discord-allowed-guilds-whitespace",
94
+ message: `gateway.adapters.discord.allowedGuilds contains ${label} with leading/trailing whitespace.`
88
95
  });
89
- continue;
90
96
  }
91
- if (hasLeadingOrTrailingWhitespace(entry)) warnings.push({
92
- code: "discord-allowed-guilds-whitespace",
93
- message: `gateway.adapters.discord.allowedGuilds contains ${label} with leading/trailing whitespace.`
97
+ }
98
+ if (teams?.enabled) {
99
+ if (!teams.appId || !teams.appPassword) warnings.push({
100
+ code: "teams-credentials-missing",
101
+ message: "gateway.adapters.teams.enabled is true but gateway.adapters.teams.appId/appPassword are not both set; the adapter will not start."
102
+ });
103
+ if (isBlank(teams.sessionCommand || "")) warnings.push({
104
+ code: "teams-session-command-blank",
105
+ message: 'gateway.adapters.teams.sessionCommand is blank; it will fall back to "!session".'
106
+ });
107
+ if (isBlank(teams.endpointPath || "")) warnings.push({
108
+ code: "teams-endpoint-path-blank",
109
+ message: 'gateway.adapters.teams.endpointPath is blank; it will fall back to "/api/adapters/teams/messages".'
94
110
  });
111
+ for (const [rawKey, rawValue] of Object.entries(teams.channelSessions ?? {})){
112
+ const keyLabel = JSON.stringify(rawKey);
113
+ const value = "string" == typeof rawValue ? rawValue : "";
114
+ const valueLabel = JSON.stringify(value);
115
+ if (hasLeadingOrTrailingWhitespace(rawKey)) warnings.push({
116
+ code: "teams-channel-sessions-key-whitespace",
117
+ message: `gateway.adapters.teams.channelSessions key ${keyLabel} has leading/trailing whitespace.`
118
+ });
119
+ if (hasLeadingOrTrailingWhitespace(value)) warnings.push({
120
+ code: "teams-channel-sessions-value-whitespace",
121
+ message: `gateway.adapters.teams.channelSessions[${keyLabel}] value ${valueLabel} has leading/trailing whitespace.`
122
+ });
123
+ if (isBlank(value)) {
124
+ warnings.push({
125
+ code: "teams-channel-sessions-value-blank",
126
+ message: `gateway.adapters.teams.channelSessions[${keyLabel}] is empty; mapping will fall back to derived session keys.`
127
+ });
128
+ continue;
129
+ }
130
+ if (!AGENT_PREFIX.test(value.trim())) warnings.push({
131
+ code: "teams-channel-sessions-missing-agent",
132
+ message: `gateway.adapters.teams.channelSessions[${keyLabel}] does not include an agent prefix (agent:<id>:...); agent selection will use bindings/default.`
133
+ });
134
+ }
135
+ for (const entry of teams.allowedChannelIds ?? []){
136
+ const label = JSON.stringify(entry);
137
+ if (isBlank(entry)) {
138
+ warnings.push({
139
+ code: "teams-allowed-channel-ids-blank",
140
+ message: "gateway.adapters.teams.allowedChannelIds contains a blank entry; remove empty strings."
141
+ });
142
+ continue;
143
+ }
144
+ if (hasLeadingOrTrailingWhitespace(entry)) warnings.push({
145
+ code: "teams-allowed-channel-ids-whitespace",
146
+ message: `gateway.adapters.teams.allowedChannelIds contains ${label} with leading/trailing whitespace.`
147
+ });
148
+ }
149
+ for (const entry of teams.allowedTeamIds ?? []){
150
+ const label = JSON.stringify(entry);
151
+ if (isBlank(entry)) {
152
+ warnings.push({
153
+ code: "teams-allowed-team-ids-blank",
154
+ message: "gateway.adapters.teams.allowedTeamIds contains a blank entry; remove empty strings."
155
+ });
156
+ continue;
157
+ }
158
+ if (hasLeadingOrTrailingWhitespace(entry)) warnings.push({
159
+ code: "teams-allowed-team-ids-whitespace",
160
+ message: `gateway.adapters.teams.allowedTeamIds contains ${label} with leading/trailing whitespace.`
161
+ });
162
+ }
95
163
  }
96
164
  return warnings;
97
165
  }
@@ -4,66 +4,134 @@ const isBlank = (value)=>0 === value.trim().length;
4
4
  function collectConfigWarnings(config) {
5
5
  const warnings = [];
6
6
  const discord = config.gateway?.adapters?.discord;
7
- if (!discord?.enabled) return warnings;
8
- if (!discord.token) warnings.push({
9
- code: "discord-token-missing",
10
- message: "gateway.adapters.discord.enabled is true but gateway.adapters.discord.token is not set; the adapter will not start."
11
- });
12
- if (isBlank(discord.sessionCommand || "")) warnings.push({
13
- code: "discord-session-command-blank",
14
- message: 'gateway.adapters.discord.sessionCommand is blank; it will fall back to "!session".'
15
- });
16
- for (const [rawKey, rawValue] of Object.entries(discord.channelSessions ?? {})){
17
- const keyLabel = JSON.stringify(rawKey);
18
- const value = "string" == typeof rawValue ? rawValue : "";
19
- const valueLabel = JSON.stringify(value);
20
- if (hasLeadingOrTrailingWhitespace(rawKey)) warnings.push({
21
- code: "discord-channel-sessions-key-whitespace",
22
- message: `gateway.adapters.discord.channelSessions key ${keyLabel} has leading/trailing whitespace.`
7
+ const teams = config.gateway?.adapters?.teams;
8
+ if (discord?.enabled) {
9
+ if (!discord.token) warnings.push({
10
+ code: "discord-token-missing",
11
+ message: "gateway.adapters.discord.enabled is true but gateway.adapters.discord.token is not set; the adapter will not start."
23
12
  });
24
- if (hasLeadingOrTrailingWhitespace(value)) warnings.push({
25
- code: "discord-channel-sessions-value-whitespace",
26
- message: `gateway.adapters.discord.channelSessions[${keyLabel}] value ${valueLabel} has leading/trailing whitespace.`
13
+ if (isBlank(discord.sessionCommand || "")) warnings.push({
14
+ code: "discord-session-command-blank",
15
+ message: 'gateway.adapters.discord.sessionCommand is blank; it will fall back to "!session".'
27
16
  });
28
- if (isBlank(value)) {
29
- warnings.push({
30
- code: "discord-channel-sessions-value-blank",
31
- message: `gateway.adapters.discord.channelSessions[${keyLabel}] is empty; mapping will fall back to derived session keys.`
17
+ for (const [rawKey, rawValue] of Object.entries(discord.channelSessions ?? {})){
18
+ const keyLabel = JSON.stringify(rawKey);
19
+ const value = "string" == typeof rawValue ? rawValue : "";
20
+ const valueLabel = JSON.stringify(value);
21
+ if (hasLeadingOrTrailingWhitespace(rawKey)) warnings.push({
22
+ code: "discord-channel-sessions-key-whitespace",
23
+ message: `gateway.adapters.discord.channelSessions key ${keyLabel} has leading/trailing whitespace.`
24
+ });
25
+ if (hasLeadingOrTrailingWhitespace(value)) warnings.push({
26
+ code: "discord-channel-sessions-value-whitespace",
27
+ message: `gateway.adapters.discord.channelSessions[${keyLabel}] value ${valueLabel} has leading/trailing whitespace.`
28
+ });
29
+ if (isBlank(value)) {
30
+ warnings.push({
31
+ code: "discord-channel-sessions-value-blank",
32
+ message: `gateway.adapters.discord.channelSessions[${keyLabel}] is empty; mapping will fall back to derived session keys.`
33
+ });
34
+ continue;
35
+ }
36
+ if (!AGENT_PREFIX.test(value.trim())) warnings.push({
37
+ code: "discord-channel-sessions-missing-agent",
38
+ message: `gateway.adapters.discord.channelSessions[${keyLabel}] does not include an agent prefix (agent:<id>:...); agent selection will use bindings/default.`
32
39
  });
33
- continue;
34
40
  }
35
- if (!AGENT_PREFIX.test(value.trim())) warnings.push({
36
- code: "discord-channel-sessions-missing-agent",
37
- message: `gateway.adapters.discord.channelSessions[${keyLabel}] does not include an agent prefix (agent:<id>:...); agent selection will use bindings/default.`
38
- });
39
- }
40
- for (const entry of discord.allowedChannels ?? []){
41
- const label = JSON.stringify(entry);
42
- if (isBlank(entry)) {
43
- warnings.push({
44
- code: "discord-allowed-channels-blank",
45
- message: "gateway.adapters.discord.allowedChannels contains a blank entry; remove empty strings."
41
+ for (const entry of discord.allowedChannels ?? []){
42
+ const label = JSON.stringify(entry);
43
+ if (isBlank(entry)) {
44
+ warnings.push({
45
+ code: "discord-allowed-channels-blank",
46
+ message: "gateway.adapters.discord.allowedChannels contains a blank entry; remove empty strings."
47
+ });
48
+ continue;
49
+ }
50
+ if (hasLeadingOrTrailingWhitespace(entry)) warnings.push({
51
+ code: "discord-allowed-channels-whitespace",
52
+ message: `gateway.adapters.discord.allowedChannels contains ${label} with leading/trailing whitespace.`
46
53
  });
47
- continue;
48
54
  }
49
- if (hasLeadingOrTrailingWhitespace(entry)) warnings.push({
50
- code: "discord-allowed-channels-whitespace",
51
- message: `gateway.adapters.discord.allowedChannels contains ${label} with leading/trailing whitespace.`
52
- });
53
- }
54
- for (const entry of discord.allowedGuilds ?? []){
55
- const label = JSON.stringify(entry);
56
- if (isBlank(entry)) {
57
- warnings.push({
58
- code: "discord-allowed-guilds-blank",
59
- message: "gateway.adapters.discord.allowedGuilds contains a blank entry; remove empty strings."
55
+ for (const entry of discord.allowedGuilds ?? []){
56
+ const label = JSON.stringify(entry);
57
+ if (isBlank(entry)) {
58
+ warnings.push({
59
+ code: "discord-allowed-guilds-blank",
60
+ message: "gateway.adapters.discord.allowedGuilds contains a blank entry; remove empty strings."
61
+ });
62
+ continue;
63
+ }
64
+ if (hasLeadingOrTrailingWhitespace(entry)) warnings.push({
65
+ code: "discord-allowed-guilds-whitespace",
66
+ message: `gateway.adapters.discord.allowedGuilds contains ${label} with leading/trailing whitespace.`
60
67
  });
61
- continue;
62
68
  }
63
- if (hasLeadingOrTrailingWhitespace(entry)) warnings.push({
64
- code: "discord-allowed-guilds-whitespace",
65
- message: `gateway.adapters.discord.allowedGuilds contains ${label} with leading/trailing whitespace.`
69
+ }
70
+ if (teams?.enabled) {
71
+ if (!teams.appId || !teams.appPassword) warnings.push({
72
+ code: "teams-credentials-missing",
73
+ message: "gateway.adapters.teams.enabled is true but gateway.adapters.teams.appId/appPassword are not both set; the adapter will not start."
74
+ });
75
+ if (isBlank(teams.sessionCommand || "")) warnings.push({
76
+ code: "teams-session-command-blank",
77
+ message: 'gateway.adapters.teams.sessionCommand is blank; it will fall back to "!session".'
78
+ });
79
+ if (isBlank(teams.endpointPath || "")) warnings.push({
80
+ code: "teams-endpoint-path-blank",
81
+ message: 'gateway.adapters.teams.endpointPath is blank; it will fall back to "/api/adapters/teams/messages".'
66
82
  });
83
+ for (const [rawKey, rawValue] of Object.entries(teams.channelSessions ?? {})){
84
+ const keyLabel = JSON.stringify(rawKey);
85
+ const value = "string" == typeof rawValue ? rawValue : "";
86
+ const valueLabel = JSON.stringify(value);
87
+ if (hasLeadingOrTrailingWhitespace(rawKey)) warnings.push({
88
+ code: "teams-channel-sessions-key-whitespace",
89
+ message: `gateway.adapters.teams.channelSessions key ${keyLabel} has leading/trailing whitespace.`
90
+ });
91
+ if (hasLeadingOrTrailingWhitespace(value)) warnings.push({
92
+ code: "teams-channel-sessions-value-whitespace",
93
+ message: `gateway.adapters.teams.channelSessions[${keyLabel}] value ${valueLabel} has leading/trailing whitespace.`
94
+ });
95
+ if (isBlank(value)) {
96
+ warnings.push({
97
+ code: "teams-channel-sessions-value-blank",
98
+ message: `gateway.adapters.teams.channelSessions[${keyLabel}] is empty; mapping will fall back to derived session keys.`
99
+ });
100
+ continue;
101
+ }
102
+ if (!AGENT_PREFIX.test(value.trim())) warnings.push({
103
+ code: "teams-channel-sessions-missing-agent",
104
+ message: `gateway.adapters.teams.channelSessions[${keyLabel}] does not include an agent prefix (agent:<id>:...); agent selection will use bindings/default.`
105
+ });
106
+ }
107
+ for (const entry of teams.allowedChannelIds ?? []){
108
+ const label = JSON.stringify(entry);
109
+ if (isBlank(entry)) {
110
+ warnings.push({
111
+ code: "teams-allowed-channel-ids-blank",
112
+ message: "gateway.adapters.teams.allowedChannelIds contains a blank entry; remove empty strings."
113
+ });
114
+ continue;
115
+ }
116
+ if (hasLeadingOrTrailingWhitespace(entry)) warnings.push({
117
+ code: "teams-allowed-channel-ids-whitespace",
118
+ message: `gateway.adapters.teams.allowedChannelIds contains ${label} with leading/trailing whitespace.`
119
+ });
120
+ }
121
+ for (const entry of teams.allowedTeamIds ?? []){
122
+ const label = JSON.stringify(entry);
123
+ if (isBlank(entry)) {
124
+ warnings.push({
125
+ code: "teams-allowed-team-ids-blank",
126
+ message: "gateway.adapters.teams.allowedTeamIds contains a blank entry; remove empty strings."
127
+ });
128
+ continue;
129
+ }
130
+ if (hasLeadingOrTrailingWhitespace(entry)) warnings.push({
131
+ code: "teams-allowed-team-ids-whitespace",
132
+ message: `gateway.adapters.teams.allowedTeamIds contains ${label} with leading/trailing whitespace.`
133
+ });
134
+ }
67
135
  }
68
136
  return warnings;
69
137
  }
@@ -57,6 +57,7 @@ const additional_messages_cjs_namespaceObject = require("../../agent/middleware/
57
57
  const merger_cjs_namespaceObject = require("../../agent/middleware/hooks/merger.cjs");
58
58
  const hooks_cjs_namespaceObject = require("../../agent/middleware/hooks.cjs");
59
59
  const media_compat_cjs_namespaceObject = require("../../agent/middleware/media-compat.cjs");
60
+ const mcp_resources_cjs_namespaceObject = require("../../agent/tools/mcp_resources.cjs");
60
61
  const terminal_session_manager_cjs_namespaceObject = require("../../agent/tools/terminal_session_manager.cjs");
61
62
  const uiRegistry_cjs_namespaceObject = require("../../agent/uiRegistry.cjs");
62
63
  const activation_cjs_namespaceObject = require("../../skills/activation.cjs");
@@ -338,6 +339,7 @@ class AgentInvoker {
338
339
  });
339
340
  const targetAgent = await loader.loadAgent(agentName);
340
341
  if (!targetAgent) throw new Error(`Agent "${agentName}" not found`);
342
+ if (options?.modelOverride && "string" == typeof options.modelOverride && options.modelOverride.trim().length > 0) targetAgent.model = options.modelOverride.trim();
341
343
  this.logger.info(`Invoking agent: ${agentName}`);
342
344
  const preview = prompt.trim() || (attachments && attachments.length > 0 ? buildAttachmentPreview(attachments) : "");
343
345
  this.outputManager.emitAgentStart(agentName, preview);
@@ -355,9 +357,14 @@ class AgentInvoker {
355
357
  });
356
358
  await this.mcpManager.initialize();
357
359
  const mcpTools = await this.mcpManager.getTools();
358
- if (mcpTools.length > 0) {
360
+ const mcpResourceTools = (0, mcp_resources_cjs_namespaceObject.createMCPResourceTools)(this.mcpManager);
361
+ const allMcpTools = [
362
+ ...mcpTools,
363
+ ...mcpResourceTools
364
+ ];
365
+ if (allMcpTools.length > 0) {
359
366
  const existing = new Set((targetAgent.tools || []).map((tool)=>tool.name));
360
- const unique = mcpTools.filter((tool)=>!existing.has(tool.name));
367
+ const unique = allMcpTools.filter((tool)=>!existing.has(tool.name));
361
368
  targetAgent.tools = [
362
369
  ...targetAgent.tools || [],
363
370
  ...unique
@@ -25,6 +25,7 @@ export interface AgentInvokerOptions {
25
25
  }
26
26
  export interface InvokeAgentOptions {
27
27
  signal?: AbortSignal;
28
+ modelOverride?: string;
28
29
  }
29
30
  export type ImageAttachment = {
30
31
  kind?: "image";
@@ -8,6 +8,7 @@ import { additionalMessageMiddleware } from "../../agent/middleware/additional-m
8
8
  import { mergeHooks } from "../../agent/middleware/hooks/merger.js";
9
9
  import { createHooksMiddleware } from "../../agent/middleware/hooks.js";
10
10
  import { mediaCompatibilityMiddleware } from "../../agent/middleware/media-compat.js";
11
+ import { createMCPResourceTools } from "../../agent/tools/mcp_resources.js";
11
12
  import { getSharedTerminalSessionManager } from "../../agent/tools/terminal_session_manager.js";
12
13
  import { getBundledSkillsPath } from "../../agent/uiRegistry.js";
13
14
  import { resolveSkillActivation } from "../../skills/activation.js";
@@ -289,6 +290,7 @@ class AgentInvoker {
289
290
  });
290
291
  const targetAgent = await loader.loadAgent(agentName);
291
292
  if (!targetAgent) throw new Error(`Agent "${agentName}" not found`);
293
+ if (options?.modelOverride && "string" == typeof options.modelOverride && options.modelOverride.trim().length > 0) targetAgent.model = options.modelOverride.trim();
292
294
  this.logger.info(`Invoking agent: ${agentName}`);
293
295
  const preview = prompt.trim() || (attachments && attachments.length > 0 ? buildAttachmentPreview(attachments) : "");
294
296
  this.outputManager.emitAgentStart(agentName, preview);
@@ -306,9 +308,14 @@ class AgentInvoker {
306
308
  });
307
309
  await this.mcpManager.initialize();
308
310
  const mcpTools = await this.mcpManager.getTools();
309
- if (mcpTools.length > 0) {
311
+ const mcpResourceTools = createMCPResourceTools(this.mcpManager);
312
+ const allMcpTools = [
313
+ ...mcpTools,
314
+ ...mcpResourceTools
315
+ ];
316
+ if (allMcpTools.length > 0) {
310
317
  const existing = new Set((targetAgent.tools || []).map((tool)=>tool.name));
311
- const unique = mcpTools.filter((tool)=>!existing.has(tool.name));
318
+ const unique = allMcpTools.filter((tool)=>!existing.has(tool.name));
312
319
  targetAgent.tools = [
313
320
  ...targetAgent.tools || [],
314
321
  ...unique
@@ -24,6 +24,8 @@ var __webpack_require__ = {};
24
24
  var __webpack_exports__ = {};
25
25
  __webpack_require__.r(__webpack_exports__);
26
26
  __webpack_require__.d(__webpack_exports__, {
27
+ removeSessionMediaDirectory: ()=>removeSessionMediaDirectory,
28
+ getSessionMediaDirectory: ()=>getSessionMediaDirectory,
27
29
  persistAssistantImagesToDisk: ()=>persistAssistantImagesToDisk,
28
30
  parseBase64DataUrl: ()=>parseBase64DataUrl,
29
31
  resolveImageExtension: ()=>resolveImageExtension
@@ -34,7 +36,7 @@ const external_node_path_namespaceObject = require("node:path");
34
36
  const DATA_URL_BASE64_PATTERN = /^data:([^;,]+);base64,(.+)$/i;
35
37
  function persistAssistantImagesToDisk(input) {
36
38
  if (!input.messages.length) return;
37
- const mediaRoot = (0, external_node_path_namespaceObject.join)((0, external_node_path_namespaceObject.dirname)(input.dbPath), "media", sanitizePathSegment(input.sessionId));
39
+ const mediaRoot = getSessionMediaDirectory(input.dbPath, input.sessionId);
38
40
  for (const message of input.messages)if ("assistant" === message.role) {
39
41
  if (Array.isArray(message.attachments) && 0 !== message.attachments.length) for (const attachment of message.attachments){
40
42
  if (!attachment || "image" !== attachment.kind) continue;
@@ -66,6 +68,16 @@ function persistAssistantImagesToDisk(input) {
66
68
  }
67
69
  }
68
70
  }
71
+ function getSessionMediaDirectory(dbPath, sessionId) {
72
+ return (0, external_node_path_namespaceObject.join)((0, external_node_path_namespaceObject.dirname)(dbPath), "media", sanitizePathSegment(sessionId));
73
+ }
74
+ function removeSessionMediaDirectory(dbPath, sessionId) {
75
+ const mediaDir = getSessionMediaDirectory(dbPath, sessionId);
76
+ (0, external_node_fs_namespaceObject.rmSync)(mediaDir, {
77
+ recursive: true,
78
+ force: true
79
+ });
80
+ }
69
81
  function parseBase64DataUrl(dataUrl) {
70
82
  if ("string" != typeof dataUrl) return null;
71
83
  const match = dataUrl.match(DATA_URL_BASE64_PATTERN);
@@ -112,12 +124,16 @@ function sanitizePathSegment(value) {
112
124
  const sanitized = normalized.replace(/[^a-zA-Z0-9._-]/g, "_");
113
125
  return sanitized.slice(0, 120) || "default-session";
114
126
  }
127
+ exports.getSessionMediaDirectory = __webpack_exports__.getSessionMediaDirectory;
115
128
  exports.parseBase64DataUrl = __webpack_exports__.parseBase64DataUrl;
116
129
  exports.persistAssistantImagesToDisk = __webpack_exports__.persistAssistantImagesToDisk;
130
+ exports.removeSessionMediaDirectory = __webpack_exports__.removeSessionMediaDirectory;
117
131
  exports.resolveImageExtension = __webpack_exports__.resolveImageExtension;
118
132
  for(var __rspack_i in __webpack_exports__)if (-1 === [
133
+ "getSessionMediaDirectory",
119
134
  "parseBase64DataUrl",
120
135
  "persistAssistantImagesToDisk",
136
+ "removeSessionMediaDirectory",
121
137
  "resolveImageExtension"
122
138
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
123
139
  Object.defineProperty(exports, '__esModule', {
@@ -19,6 +19,8 @@ export declare function persistAssistantImagesToDisk(input: {
19
19
  sessionId: string;
20
20
  messages: PersistableMessage[];
21
21
  }): void;
22
+ export declare function getSessionMediaDirectory(dbPath: string, sessionId: string): string;
23
+ export declare function removeSessionMediaDirectory(dbPath: string, sessionId: string): void;
22
24
  export declare function parseBase64DataUrl(dataUrl: string): ParsedDataUrl | null;
23
25
  export declare function resolveImageExtension(mimeType: string): string;
24
26
  export {};
@@ -1,10 +1,10 @@
1
1
  import { createHash } from "node:crypto";
2
- import { existsSync, mkdirSync, writeFileSync } from "node:fs";
2
+ import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
3
3
  import { dirname, join } from "node:path";
4
4
  const DATA_URL_BASE64_PATTERN = /^data:([^;,]+);base64,(.+)$/i;
5
5
  function persistAssistantImagesToDisk(input) {
6
6
  if (!input.messages.length) return;
7
- const mediaRoot = join(dirname(input.dbPath), "media", sanitizePathSegment(input.sessionId));
7
+ const mediaRoot = getSessionMediaDirectory(input.dbPath, input.sessionId);
8
8
  for (const message of input.messages)if ("assistant" === message.role) {
9
9
  if (Array.isArray(message.attachments) && 0 !== message.attachments.length) for (const attachment of message.attachments){
10
10
  if (!attachment || "image" !== attachment.kind) continue;
@@ -36,6 +36,16 @@ function persistAssistantImagesToDisk(input) {
36
36
  }
37
37
  }
38
38
  }
39
+ function getSessionMediaDirectory(dbPath, sessionId) {
40
+ return join(dirname(dbPath), "media", sanitizePathSegment(sessionId));
41
+ }
42
+ function removeSessionMediaDirectory(dbPath, sessionId) {
43
+ const mediaDir = getSessionMediaDirectory(dbPath, sessionId);
44
+ rmSync(mediaDir, {
45
+ recursive: true,
46
+ force: true
47
+ });
48
+ }
39
49
  function parseBase64DataUrl(dataUrl) {
40
50
  if ("string" != typeof dataUrl) return null;
41
51
  const match = dataUrl.match(DATA_URL_BASE64_PATTERN);
@@ -82,4 +92,4 @@ function sanitizePathSegment(value) {
82
92
  const sanitized = normalized.replace(/[^a-zA-Z0-9._-]/g, "_");
83
93
  return sanitized.slice(0, 120) || "default-session";
84
94
  }
85
- export { parseBase64DataUrl, persistAssistantImagesToDisk, resolveImageExtension };
95
+ export { getSessionMediaDirectory, parseBase64DataUrl, persistAssistantImagesToDisk, removeSessionMediaDirectory, resolveImageExtension };
@@ -227,6 +227,7 @@ class SessionManager {
227
227
  writesStmt.run(sessionId);
228
228
  const pendingStmt = this.db.prepare("DELETE FROM session_pending_messages WHERE session_id = ?");
229
229
  pendingStmt.run(sessionId);
230
+ (0, external_imagePersistence_cjs_namespaceObject.removeSessionMediaDirectory)(this.dbPath, sessionId);
230
231
  }
231
232
  clearSessionMessages(sessionId) {
232
233
  if (!this.db || !this.checkpointer) throw new Error("SessionManager not initialized");
@@ -242,6 +243,7 @@ class SessionManager {
242
243
  WHERE id = ?
243
244
  `);
244
245
  sessionStmt.run(Date.now(), sessionId);
246
+ (0, external_imagePersistence_cjs_namespaceObject.removeSessionMediaDirectory)(this.dbPath, sessionId);
245
247
  }
246
248
  persistPendingMessage(input) {
247
249
  if (!this.db) throw new Error("SessionManager not initialized");
@@ -1,7 +1,7 @@
1
1
  import { SqliteSaver } from "@langchain/langgraph-checkpoint-sqlite";
2
2
  import { createDeepAgent } from "deepagents";
3
3
  import { v4 } from "uuid";
4
- import { persistAssistantImagesToDisk } from "./imagePersistence.js";
4
+ import { persistAssistantImagesToDisk, removeSessionMediaDirectory } from "./imagePersistence.js";
5
5
  function _define_property(obj, key, value) {
6
6
  if (key in obj) Object.defineProperty(obj, key, {
7
7
  value: value,
@@ -194,6 +194,7 @@ class SessionManager {
194
194
  writesStmt.run(sessionId);
195
195
  const pendingStmt = this.db.prepare("DELETE FROM session_pending_messages WHERE session_id = ?");
196
196
  pendingStmt.run(sessionId);
197
+ removeSessionMediaDirectory(this.dbPath, sessionId);
197
198
  }
198
199
  clearSessionMessages(sessionId) {
199
200
  if (!this.db || !this.checkpointer) throw new Error("SessionManager not initialized");
@@ -209,6 +210,7 @@ class SessionManager {
209
210
  WHERE id = ?
210
211
  `);
211
212
  sessionStmt.run(Date.now(), sessionId);
213
+ removeSessionMediaDirectory(this.dbPath, sessionId);
212
214
  }
213
215
  persistPendingMessage(input) {
214
216
  if (!this.db) throw new Error("SessionManager not initialized");
@@ -66,6 +66,24 @@ export interface WingmanConfig {
66
66
  gatewayPassword?: string;
67
67
  responseChunkSize?: number;
68
68
  };
69
+ teams?: {
70
+ enabled?: boolean;
71
+ appId?: string;
72
+ appPassword?: string;
73
+ appType?: "MultiTenant" | "SingleTenant" | "UserAssignedMsi" | "UserAssignedMSI";
74
+ tenantId?: string;
75
+ endpointPath?: string;
76
+ mentionOnly?: boolean;
77
+ allowBots?: boolean;
78
+ allowedTeamIds?: string[];
79
+ allowedChannelIds?: string[];
80
+ channelSessions?: Record<string, string>;
81
+ sessionCommand?: string;
82
+ gatewayUrl?: string;
83
+ gatewayToken?: string;
84
+ gatewayPassword?: string;
85
+ responseChunkSize?: number;
86
+ };
69
87
  };
70
88
  };
71
89
  agents?: {