@wingman-ai/gateway 0.5.3 → 0.5.4

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 (311) hide show
  1. package/dist/agent/config/agentConfig.cjs +4 -0
  2. package/dist/agent/config/agentConfig.d.ts +12 -0
  3. package/dist/agent/config/agentConfig.js +4 -0
  4. package/dist/agent/config/toolRegistry.cjs +75 -1
  5. package/dist/agent/config/toolRegistry.d.ts +3 -0
  6. package/dist/agent/config/toolRegistry.js +75 -1
  7. package/dist/agent/middleware/large-tool-results.cjs +207 -0
  8. package/dist/agent/middleware/large-tool-results.d.ts +16 -0
  9. package/dist/agent/middleware/large-tool-results.js +173 -0
  10. package/dist/agent/tools/browser_control.cjs +9 -1231
  11. package/dist/agent/tools/browser_control.d.ts +126 -234
  12. package/dist/agent/tools/browser_control.js +7 -1226
  13. package/dist/agent/tools/browser_runtime.cjs +1189 -0
  14. package/dist/agent/tools/browser_runtime.d.ts +560 -0
  15. package/dist/agent/tools/browser_runtime.js +1122 -0
  16. package/dist/agent/tools/browser_session.cjs +153 -0
  17. package/dist/agent/tools/browser_session.d.ts +741 -0
  18. package/dist/agent/tools/browser_session.js +110 -0
  19. package/dist/agent/tools/browser_session_manager.cjs +202 -0
  20. package/dist/agent/tools/browser_session_manager.d.ts +64 -0
  21. package/dist/agent/tools/browser_session_manager.js +165 -0
  22. package/dist/cli/commands/init.cjs +5 -1
  23. package/dist/cli/commands/init.js +5 -1
  24. package/dist/cli/config/loader.cjs +0 -5
  25. package/dist/cli/config/loader.js +0 -5
  26. package/dist/cli/config/schema.cjs +3 -7
  27. package/dist/cli/config/schema.d.ts +6 -6
  28. package/dist/cli/config/schema.js +3 -7
  29. package/dist/cli/core/agentInvoker.cjs +86 -22
  30. package/dist/cli/core/agentInvoker.d.ts +10 -3
  31. package/dist/cli/core/agentInvoker.js +86 -25
  32. package/dist/cli/core/outputManager.cjs +7 -2
  33. package/dist/cli/core/outputManager.d.ts +2 -2
  34. package/dist/cli/core/outputManager.js +7 -2
  35. package/dist/cli/types.d.ts +2 -1
  36. package/dist/webui/assets/index-XrEnkZiq.css +11 -0
  37. package/dist/webui/assets/index-mDs6HbKM.js +215 -0
  38. package/dist/webui/index.html +2 -2
  39. package/package.json +10 -10
  40. package/templates/agents/README.md +2 -1
  41. package/templates/agents/coding/agent.md +6 -13
  42. package/templates/agents/coding-v2/agent.md +6 -1
  43. package/templates/agents/game-dev/agent.md +8 -2
  44. package/templates/agents/game-dev/game-designer.md +4 -0
  45. package/templates/agents/game-dev/scene-engineer.md +4 -0
  46. package/templates/agents/main/agent.md +5 -0
  47. package/templates/agents/researcher/agent.md +11 -0
  48. package/templates/agents/stock-trader/agent.md +4 -0
  49. package/dist/agent/tests/agentConfig.test.cjs +0 -224
  50. package/dist/agent/tests/agentConfig.test.d.ts +0 -1
  51. package/dist/agent/tests/agentConfig.test.js +0 -218
  52. package/dist/agent/tests/agentLoader.test.cjs +0 -335
  53. package/dist/agent/tests/agentLoader.test.d.ts +0 -1
  54. package/dist/agent/tests/agentLoader.test.js +0 -329
  55. package/dist/agent/tests/backgroundTerminal.test.cjs +0 -70
  56. package/dist/agent/tests/backgroundTerminal.test.d.ts +0 -1
  57. package/dist/agent/tests/backgroundTerminal.test.js +0 -64
  58. package/dist/agent/tests/browserControlHelpers.test.cjs +0 -35
  59. package/dist/agent/tests/browserControlHelpers.test.d.ts +0 -1
  60. package/dist/agent/tests/browserControlHelpers.test.js +0 -29
  61. package/dist/agent/tests/browserControlTool.test.cjs +0 -2117
  62. package/dist/agent/tests/browserControlTool.test.d.ts +0 -1
  63. package/dist/agent/tests/browserControlTool.test.js +0 -2111
  64. package/dist/agent/tests/commandExecuteTool.test.cjs +0 -29
  65. package/dist/agent/tests/commandExecuteTool.test.d.ts +0 -1
  66. package/dist/agent/tests/commandExecuteTool.test.js +0 -23
  67. package/dist/agent/tests/internet_search.test.cjs +0 -107
  68. package/dist/agent/tests/internet_search.test.d.ts +0 -1
  69. package/dist/agent/tests/internet_search.test.js +0 -101
  70. package/dist/agent/tests/mcpClientManager.test.cjs +0 -290
  71. package/dist/agent/tests/mcpClientManager.test.d.ts +0 -1
  72. package/dist/agent/tests/mcpClientManager.test.js +0 -284
  73. package/dist/agent/tests/mcpResourceTools.test.cjs +0 -101
  74. package/dist/agent/tests/mcpResourceTools.test.d.ts +0 -1
  75. package/dist/agent/tests/mcpResourceTools.test.js +0 -95
  76. package/dist/agent/tests/modelFactory.test.cjs +0 -190
  77. package/dist/agent/tests/modelFactory.test.d.ts +0 -1
  78. package/dist/agent/tests/modelFactory.test.js +0 -184
  79. package/dist/agent/tests/terminalSessionManager.test.cjs +0 -121
  80. package/dist/agent/tests/terminalSessionManager.test.d.ts +0 -1
  81. package/dist/agent/tests/terminalSessionManager.test.js +0 -115
  82. package/dist/agent/tests/test-agent-loader.cjs +0 -33
  83. package/dist/agent/tests/test-agent-loader.d.ts +0 -1
  84. package/dist/agent/tests/test-agent-loader.js +0 -27
  85. package/dist/agent/tests/test-subagent-loading.cjs +0 -99
  86. package/dist/agent/tests/test-subagent-loading.d.ts +0 -1
  87. package/dist/agent/tests/test-subagent-loading.js +0 -93
  88. package/dist/agent/tests/toolRegistry.test.cjs +0 -147
  89. package/dist/agent/tests/toolRegistry.test.d.ts +0 -1
  90. package/dist/agent/tests/toolRegistry.test.js +0 -141
  91. package/dist/agent/tests/uiRegistryTools.test.cjs +0 -114
  92. package/dist/agent/tests/uiRegistryTools.test.d.ts +0 -1
  93. package/dist/agent/tests/uiRegistryTools.test.js +0 -105
  94. package/dist/agent/tests/xaiImageModel.test.cjs +0 -194
  95. package/dist/agent/tests/xaiImageModel.test.d.ts +0 -1
  96. package/dist/agent/tests/xaiImageModel.test.js +0 -188
  97. package/dist/tests/additionalMessageMiddleware.test.cjs +0 -216
  98. package/dist/tests/additionalMessageMiddleware.test.d.ts +0 -1
  99. package/dist/tests/additionalMessageMiddleware.test.js +0 -188
  100. package/dist/tests/agent-config-voice.test.cjs +0 -25
  101. package/dist/tests/agent-config-voice.test.d.ts +0 -1
  102. package/dist/tests/agent-config-voice.test.js +0 -19
  103. package/dist/tests/agentInvokerAttachments.test.cjs +0 -190
  104. package/dist/tests/agentInvokerAttachments.test.d.ts +0 -1
  105. package/dist/tests/agentInvokerAttachments.test.js +0 -184
  106. package/dist/tests/agentInvokerSummarization.test.cjs +0 -613
  107. package/dist/tests/agentInvokerSummarization.test.d.ts +0 -1
  108. package/dist/tests/agentInvokerSummarization.test.js +0 -607
  109. package/dist/tests/agentInvokerTokenUsage.test.cjs +0 -124
  110. package/dist/tests/agentInvokerTokenUsage.test.d.ts +0 -1
  111. package/dist/tests/agentInvokerTokenUsage.test.js +0 -118
  112. package/dist/tests/agentInvokerWorkdir.test.cjs +0 -150
  113. package/dist/tests/agentInvokerWorkdir.test.d.ts +0 -1
  114. package/dist/tests/agentInvokerWorkdir.test.js +0 -122
  115. package/dist/tests/agents-api.test.cjs +0 -324
  116. package/dist/tests/agents-api.test.d.ts +0 -1
  117. package/dist/tests/agents-api.test.js +0 -318
  118. package/dist/tests/attachments-utils.test.cjs +0 -46
  119. package/dist/tests/attachments-utils.test.d.ts +0 -1
  120. package/dist/tests/attachments-utils.test.js +0 -40
  121. package/dist/tests/browser-command.test.cjs +0 -264
  122. package/dist/tests/browser-command.test.d.ts +0 -1
  123. package/dist/tests/browser-command.test.js +0 -258
  124. package/dist/tests/browser-relay-server.test.cjs +0 -20
  125. package/dist/tests/browser-relay-server.test.d.ts +0 -1
  126. package/dist/tests/browser-relay-server.test.js +0 -14
  127. package/dist/tests/bunSqliteAdapter.test.cjs +0 -265
  128. package/dist/tests/bunSqliteAdapter.test.d.ts +0 -1
  129. package/dist/tests/bunSqliteAdapter.test.js +0 -259
  130. package/dist/tests/candleRange.test.cjs +0 -48
  131. package/dist/tests/candleRange.test.d.ts +0 -1
  132. package/dist/tests/candleRange.test.js +0 -42
  133. package/dist/tests/cli-config-loader.test.cjs +0 -532
  134. package/dist/tests/cli-config-loader.test.d.ts +0 -1
  135. package/dist/tests/cli-config-loader.test.js +0 -526
  136. package/dist/tests/cli-config-warnings.test.cjs +0 -94
  137. package/dist/tests/cli-config-warnings.test.d.ts +0 -1
  138. package/dist/tests/cli-config-warnings.test.js +0 -88
  139. package/dist/tests/cli-init.test.cjs +0 -225
  140. package/dist/tests/cli-init.test.d.ts +0 -1
  141. package/dist/tests/cli-init.test.js +0 -219
  142. package/dist/tests/cli-workspace-root.test.cjs +0 -114
  143. package/dist/tests/cli-workspace-root.test.d.ts +0 -1
  144. package/dist/tests/cli-workspace-root.test.js +0 -108
  145. package/dist/tests/codex-credentials-precedence.test.cjs +0 -94
  146. package/dist/tests/codex-credentials-precedence.test.d.ts +0 -1
  147. package/dist/tests/codex-credentials-precedence.test.js +0 -88
  148. package/dist/tests/codex-provider.test.cjs +0 -383
  149. package/dist/tests/codex-provider.test.d.ts +0 -1
  150. package/dist/tests/codex-provider.test.js +0 -377
  151. package/dist/tests/config-json-schema.test.cjs +0 -37
  152. package/dist/tests/config-json-schema.test.d.ts +0 -1
  153. package/dist/tests/config-json-schema.test.js +0 -31
  154. package/dist/tests/discord-adapter.test.cjs +0 -89
  155. package/dist/tests/discord-adapter.test.d.ts +0 -1
  156. package/dist/tests/discord-adapter.test.js +0 -83
  157. package/dist/tests/falRuntime.test.cjs +0 -78
  158. package/dist/tests/falRuntime.test.d.ts +0 -1
  159. package/dist/tests/falRuntime.test.js +0 -72
  160. package/dist/tests/falSummary.test.cjs +0 -51
  161. package/dist/tests/falSummary.test.d.ts +0 -1
  162. package/dist/tests/falSummary.test.js +0 -45
  163. package/dist/tests/fs-api.test.cjs +0 -138
  164. package/dist/tests/fs-api.test.d.ts +0 -1
  165. package/dist/tests/fs-api.test.js +0 -132
  166. package/dist/tests/gateway-command-workspace.test.cjs +0 -150
  167. package/dist/tests/gateway-command-workspace.test.d.ts +0 -1
  168. package/dist/tests/gateway-command-workspace.test.js +0 -144
  169. package/dist/tests/gateway-http-security.test.cjs +0 -318
  170. package/dist/tests/gateway-http-security.test.d.ts +0 -1
  171. package/dist/tests/gateway-http-security.test.js +0 -312
  172. package/dist/tests/gateway-node-mode.test.cjs +0 -174
  173. package/dist/tests/gateway-node-mode.test.d.ts +0 -1
  174. package/dist/tests/gateway-node-mode.test.js +0 -168
  175. package/dist/tests/gateway-origin-policy.test.cjs +0 -82
  176. package/dist/tests/gateway-origin-policy.test.d.ts +0 -1
  177. package/dist/tests/gateway-origin-policy.test.js +0 -76
  178. package/dist/tests/gateway-request-execution-overrides.test.cjs +0 -42
  179. package/dist/tests/gateway-request-execution-overrides.test.d.ts +0 -1
  180. package/dist/tests/gateway-request-execution-overrides.test.js +0 -36
  181. package/dist/tests/gateway.test.cjs +0 -700
  182. package/dist/tests/gateway.test.d.ts +0 -1
  183. package/dist/tests/gateway.test.js +0 -694
  184. package/dist/tests/hooks-matcher.test.cjs +0 -309
  185. package/dist/tests/hooks-matcher.test.d.ts +0 -1
  186. package/dist/tests/hooks-matcher.test.js +0 -303
  187. package/dist/tests/hooks-merger.test.cjs +0 -528
  188. package/dist/tests/hooks-merger.test.d.ts +0 -1
  189. package/dist/tests/hooks-merger.test.js +0 -522
  190. package/dist/tests/imagePersistence.test.cjs +0 -169
  191. package/dist/tests/imagePersistence.test.d.ts +0 -1
  192. package/dist/tests/imagePersistence.test.js +0 -163
  193. package/dist/tests/integration/agent-invocation.integration.test.cjs +0 -264
  194. package/dist/tests/integration/agent-invocation.integration.test.d.ts +0 -1
  195. package/dist/tests/integration/agent-invocation.integration.test.js +0 -258
  196. package/dist/tests/integration/finnhub-candles.integration.test.cjs +0 -98
  197. package/dist/tests/integration/finnhub-candles.integration.test.d.ts +0 -1
  198. package/dist/tests/integration/finnhub-candles.integration.test.js +0 -92
  199. package/dist/tests/integration/summarization-e2e.integration.test.cjs +0 -127
  200. package/dist/tests/integration/summarization-e2e.integration.test.d.ts +0 -1
  201. package/dist/tests/integration/summarization-e2e.integration.test.js +0 -121
  202. package/dist/tests/logger.test.cjs +0 -353
  203. package/dist/tests/logger.test.d.ts +0 -1
  204. package/dist/tests/logger.test.js +0 -347
  205. package/dist/tests/mediaCompatibilityMiddleware.test.cjs +0 -106
  206. package/dist/tests/mediaCompatibilityMiddleware.test.d.ts +0 -1
  207. package/dist/tests/mediaCompatibilityMiddleware.test.js +0 -100
  208. package/dist/tests/node-tools.test.cjs +0 -77
  209. package/dist/tests/node-tools.test.d.ts +0 -1
  210. package/dist/tests/node-tools.test.js +0 -71
  211. package/dist/tests/nodes-api.test.cjs +0 -86
  212. package/dist/tests/nodes-api.test.d.ts +0 -1
  213. package/dist/tests/nodes-api.test.js +0 -80
  214. package/dist/tests/outputManagerContextSummarized.test.cjs +0 -43
  215. package/dist/tests/outputManagerContextSummarized.test.d.ts +0 -1
  216. package/dist/tests/outputManagerContextSummarized.test.js +0 -37
  217. package/dist/tests/provider-command-codex.test.cjs +0 -57
  218. package/dist/tests/provider-command-codex.test.d.ts +0 -1
  219. package/dist/tests/provider-command-codex.test.js +0 -51
  220. package/dist/tests/routines-api.test.cjs +0 -107
  221. package/dist/tests/routines-api.test.d.ts +0 -1
  222. package/dist/tests/routines-api.test.js +0 -101
  223. package/dist/tests/run-terminal-bench-official-script.test.cjs +0 -61
  224. package/dist/tests/run-terminal-bench-official-script.test.d.ts +0 -1
  225. package/dist/tests/run-terminal-bench-official-script.test.js +0 -55
  226. package/dist/tests/sessionManager-uionly.test.cjs +0 -50
  227. package/dist/tests/sessionManager-uionly.test.d.ts +0 -1
  228. package/dist/tests/sessionManager-uionly.test.js +0 -44
  229. package/dist/tests/sessionMessageAttachments.test.cjs +0 -197
  230. package/dist/tests/sessionMessageAttachments.test.d.ts +0 -1
  231. package/dist/tests/sessionMessageAttachments.test.js +0 -191
  232. package/dist/tests/sessionMessageRole.test.cjs +0 -44
  233. package/dist/tests/sessionMessageRole.test.d.ts +0 -1
  234. package/dist/tests/sessionMessageRole.test.js +0 -38
  235. package/dist/tests/sessionStateMessages.test.cjs +0 -236
  236. package/dist/tests/sessionStateMessages.test.d.ts +0 -1
  237. package/dist/tests/sessionStateMessages.test.js +0 -230
  238. package/dist/tests/sessions-api.test.cjs +0 -250
  239. package/dist/tests/sessions-api.test.d.ts +0 -1
  240. package/dist/tests/sessions-api.test.js +0 -244
  241. package/dist/tests/skill-activation.test.cjs +0 -86
  242. package/dist/tests/skill-activation.test.d.ts +0 -1
  243. package/dist/tests/skill-activation.test.js +0 -80
  244. package/dist/tests/skill-metadata.test.cjs +0 -119
  245. package/dist/tests/skill-metadata.test.d.ts +0 -1
  246. package/dist/tests/skill-metadata.test.js +0 -113
  247. package/dist/tests/skill-repository.test.cjs +0 -469
  248. package/dist/tests/skill-repository.test.d.ts +0 -1
  249. package/dist/tests/skill-repository.test.js +0 -463
  250. package/dist/tests/skill-security-scanner.test.cjs +0 -126
  251. package/dist/tests/skill-security-scanner.test.d.ts +0 -1
  252. package/dist/tests/skill-security-scanner.test.js +0 -120
  253. package/dist/tests/sms-api.test.cjs +0 -183
  254. package/dist/tests/sms-api.test.d.ts +0 -1
  255. package/dist/tests/sms-api.test.js +0 -177
  256. package/dist/tests/sms-commands.test.cjs +0 -90
  257. package/dist/tests/sms-commands.test.d.ts +0 -1
  258. package/dist/tests/sms-commands.test.js +0 -84
  259. package/dist/tests/sms-policy-store.test.cjs +0 -69
  260. package/dist/tests/sms-policy-store.test.d.ts +0 -1
  261. package/dist/tests/sms-policy-store.test.js +0 -63
  262. package/dist/tests/teams-adapter.test.cjs +0 -58
  263. package/dist/tests/teams-adapter.test.d.ts +0 -1
  264. package/dist/tests/teams-adapter.test.js +0 -52
  265. package/dist/tests/technicalIndicators.test.cjs +0 -82
  266. package/dist/tests/technicalIndicators.test.d.ts +0 -1
  267. package/dist/tests/technicalIndicators.test.js +0 -76
  268. package/dist/tests/terminal-bench-adapters-helpers.test.cjs +0 -64
  269. package/dist/tests/terminal-bench-adapters-helpers.test.d.ts +0 -1
  270. package/dist/tests/terminal-bench-adapters-helpers.test.js +0 -58
  271. package/dist/tests/terminal-bench-cleanup.test.cjs +0 -93
  272. package/dist/tests/terminal-bench-cleanup.test.d.ts +0 -1
  273. package/dist/tests/terminal-bench-cleanup.test.js +0 -87
  274. package/dist/tests/terminal-bench-config.test.cjs +0 -62
  275. package/dist/tests/terminal-bench-config.test.d.ts +0 -1
  276. package/dist/tests/terminal-bench-config.test.js +0 -56
  277. package/dist/tests/terminal-bench-official.test.cjs +0 -194
  278. package/dist/tests/terminal-bench-official.test.d.ts +0 -1
  279. package/dist/tests/terminal-bench-official.test.js +0 -188
  280. package/dist/tests/terminal-bench-runner.test.cjs +0 -82
  281. package/dist/tests/terminal-bench-runner.test.d.ts +0 -1
  282. package/dist/tests/terminal-bench-runner.test.js +0 -76
  283. package/dist/tests/terminal-bench-scoring.test.cjs +0 -128
  284. package/dist/tests/terminal-bench-scoring.test.d.ts +0 -1
  285. package/dist/tests/terminal-bench-scoring.test.js +0 -122
  286. package/dist/tests/terminalProbe.test.cjs +0 -45
  287. package/dist/tests/terminalProbe.test.d.ts +0 -1
  288. package/dist/tests/terminalProbe.test.js +0 -39
  289. package/dist/tests/terminalProbeAuth.test.cjs +0 -85
  290. package/dist/tests/terminalProbeAuth.test.d.ts +0 -1
  291. package/dist/tests/terminalProbeAuth.test.js +0 -79
  292. package/dist/tests/toolDisplayHelpers.test.cjs +0 -46
  293. package/dist/tests/toolDisplayHelpers.test.d.ts +0 -1
  294. package/dist/tests/toolDisplayHelpers.test.js +0 -40
  295. package/dist/tests/uv.test.cjs +0 -47
  296. package/dist/tests/uv.test.d.ts +0 -1
  297. package/dist/tests/uv.test.js +0 -41
  298. package/dist/tests/voice-config.test.cjs +0 -35
  299. package/dist/tests/voice-config.test.d.ts +0 -1
  300. package/dist/tests/voice-config.test.js +0 -29
  301. package/dist/tests/websocket-transport.test.cjs +0 -31
  302. package/dist/tests/websocket-transport.test.d.ts +0 -1
  303. package/dist/tests/websocket-transport.test.js +0 -25
  304. package/dist/tests/yahooCandles.test.cjs +0 -111
  305. package/dist/tests/yahooCandles.test.d.ts +0 -1
  306. package/dist/tests/yahooCandles.test.js +0 -105
  307. package/dist/tools/finance/optionsAnalytics.test.cjs +0 -128
  308. package/dist/tools/finance/optionsAnalytics.test.d.ts +0 -1
  309. package/dist/tools/finance/optionsAnalytics.test.js +0 -122
  310. package/dist/webui/assets/index-BMf95nv5.js +0 -215
  311. package/dist/webui/assets/index-DhJQ8Mbn.css +0 -11
@@ -1,694 +0,0 @@
1
- import { mkdtempSync, rmSync } from "node:fs";
2
- import { tmpdir } from "node:os";
3
- import { join } from "node:path";
4
- import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
5
- import { GatewayClient, GatewayServer } from "../gateway/index.js";
6
- function _define_property(obj, key, value) {
7
- if (key in obj) Object.defineProperty(obj, key, {
8
- value: value,
9
- enumerable: true,
10
- configurable: true,
11
- writable: true
12
- });
13
- else obj[key] = value;
14
- return obj;
15
- }
16
- const isBun = void 0 !== globalThis.Bun;
17
- const describeIfBun = isBun ? describe : describe.skip;
18
- const invokerConstructOptions = [];
19
- vi.mock("@/cli/core/agentInvoker.js", ()=>({
20
- AgentInvoker: class {
21
- async invokeAgent(_agentId, content, _sessionId, _attachments, options) {
22
- if ("throw-no-event" === content) throw new Error("Synthetic invocation failure");
23
- if ("stream-model-failure-no-error" === content) {
24
- this.outputManager?.emitAgentStream?.({
25
- event: "on_chain_end",
26
- run_id: "model-failure-run-1",
27
- name: "ChannelWrite<branch:to:todoListMiddleware.after_model>",
28
- data: {
29
- output: [
30
- {
31
- lg_name: "Command",
32
- update: {
33
- messages: [
34
- {
35
- type: "constructor",
36
- id: [
37
- "langchain_core",
38
- "messages",
39
- "AIMessage"
40
- ],
41
- kwargs: {
42
- id: "model-failure-msg-1",
43
- 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"
44
- }
45
- }
46
- ]
47
- }
48
- }
49
- ],
50
- input: {}
51
- }
52
- });
53
- return {
54
- streaming: true
55
- };
56
- }
57
- const signal = options?.signal;
58
- await new Promise((resolve)=>{
59
- const timer = setTimeout(resolve, 75);
60
- if (signal) {
61
- const onAbort = ()=>{
62
- clearTimeout(timer);
63
- resolve();
64
- };
65
- if (signal.aborted) return void onAbort();
66
- signal.addEventListener("abort", onAbort, {
67
- once: true
68
- });
69
- }
70
- });
71
- if (signal?.aborted) {
72
- this.outputManager?.emitAgentError?.("Request cancelled");
73
- return {
74
- cancelled: true
75
- };
76
- }
77
- if ("return-no-event" === content) return {
78
- streaming: true
79
- };
80
- this.outputManager?.emitAgentComplete?.({
81
- streaming: true
82
- });
83
- return {
84
- streaming: true
85
- };
86
- }
87
- constructor(options){
88
- _define_property(this, "outputManager", void 0);
89
- this.outputManager = options?.outputManager;
90
- invokerConstructOptions.push(options || {});
91
- }
92
- }
93
- }));
94
- describeIfBun("Gateway", ()=>{
95
- let server;
96
- let port = 0;
97
- let testWorkspace;
98
- beforeAll(async ()=>{
99
- invokerConstructOptions.length = 0;
100
- testWorkspace = mkdtempSync(join(tmpdir(), "wingman-gateway-test-"));
101
- const instance = new GatewayServer({
102
- port: 0,
103
- host: "localhost",
104
- requireAuth: false,
105
- auth: {
106
- mode: "none"
107
- },
108
- logLevel: "silent",
109
- workspace: testWorkspace,
110
- configDir: ".wingman-test-config",
111
- stateDir: ".wingman-test-state"
112
- });
113
- await instance.start();
114
- server = instance;
115
- port = server.getPort();
116
- if (!port) throw new Error("Unable to determine gateway server port");
117
- await new Promise((resolve)=>setTimeout(resolve, 500));
118
- });
119
- afterAll(async ()=>{
120
- if (server) await server.stop();
121
- if (testWorkspace) rmSync(testWorkspace, {
122
- recursive: true,
123
- force: true
124
- });
125
- });
126
- const connectClient = (instanceId, clientType = "test")=>new Promise((resolve, reject)=>{
127
- const ws = new WebSocket(`ws://localhost:${port}/ws`);
128
- const connectId = `connect-${instanceId}-${Date.now()}`;
129
- const timeout = setTimeout(()=>reject(new Error("Connect timeout")), 5000);
130
- ws.addEventListener("open", ()=>{
131
- const message = {
132
- type: "connect",
133
- id: connectId,
134
- client: {
135
- instanceId,
136
- clientType
137
- },
138
- timestamp: Date.now()
139
- };
140
- ws.send(JSON.stringify(message));
141
- });
142
- ws.addEventListener("message", (event)=>{
143
- const msg = JSON.parse(event.data);
144
- if ("res" === msg.type && msg.id === connectId && msg.ok) {
145
- clearTimeout(timeout);
146
- resolve(ws);
147
- }
148
- });
149
- ws.addEventListener("error", ()=>{
150
- clearTimeout(timeout);
151
- reject(new Error("WebSocket error"));
152
- });
153
- });
154
- const waitForMessage = (ws, predicate, timeoutMs = 5000)=>new Promise((resolve, reject)=>{
155
- const timeout = setTimeout(()=>reject(new Error("Message timeout")), timeoutMs);
156
- const handler = (event)=>{
157
- let msg;
158
- try {
159
- msg = JSON.parse(event.data);
160
- } catch {
161
- return;
162
- }
163
- if (!predicate(msg)) return;
164
- clearTimeout(timeout);
165
- ws.removeEventListener("message", handler);
166
- resolve(msg);
167
- };
168
- ws.addEventListener("message", handler);
169
- });
170
- const collectMessages = (ws, predicate, durationMs = 600)=>new Promise((resolve)=>{
171
- const matches = [];
172
- const handler = (event)=>{
173
- let msg;
174
- try {
175
- msg = JSON.parse(event.data);
176
- } catch {
177
- return;
178
- }
179
- if (!predicate(msg)) return;
180
- matches.push(msg);
181
- };
182
- ws.addEventListener("message", handler);
183
- setTimeout(()=>{
184
- ws.removeEventListener("message", handler);
185
- resolve(matches);
186
- }, durationMs);
187
- });
188
- it("should start the gateway server", async ()=>{
189
- const response = await fetch(`http://localhost:${port}/health`);
190
- expect(response.ok).toBe(true);
191
- const health = await response.json();
192
- expect(health.status).toBe("healthy");
193
- });
194
- it("should connect a client", async ()=>new Promise((resolve, reject)=>{
195
- const client = new GatewayClient(`ws://localhost:${port}/ws`, "test-client", {
196
- events: {
197
- connected: ()=>{
198
- client.disconnect();
199
- resolve();
200
- },
201
- error: (error)=>{
202
- reject(new Error(error.message));
203
- }
204
- }
205
- });
206
- client.connect().catch(reject);
207
- setTimeout(()=>reject(new Error("Connection timeout")), 5000);
208
- }));
209
- it("should register a client and receive node ID", async ()=>new Promise((resolve, reject)=>{
210
- const client = new GatewayClient(`ws://localhost:${port}/ws`, "test-client-2", {
211
- events: {
212
- registered: (nodeId, name)=>{
213
- expect(nodeId).toBeTruthy();
214
- expect(name).toBe("test-client-2");
215
- client.disconnect();
216
- resolve();
217
- },
218
- error: (error)=>{
219
- reject(new Error(error.message));
220
- }
221
- }
222
- });
223
- client.connect().catch(reject);
224
- setTimeout(()=>reject(new Error("Registration timeout")), 5000);
225
- }));
226
- it("should join a broadcast group", async ()=>new Promise((resolve, reject)=>{
227
- const client = new GatewayClient(`ws://localhost:${port}/ws`, "test-client-3", {
228
- events: {
229
- registered: async ()=>{
230
- await client.joinGroup("test-group");
231
- },
232
- joinedGroup: (groupId, groupName)=>{
233
- expect(groupName).toBe("test-group");
234
- client.disconnect();
235
- resolve();
236
- },
237
- error: (error)=>{
238
- reject(new Error(error.message));
239
- }
240
- }
241
- });
242
- client.connect().catch(reject);
243
- setTimeout(()=>reject(new Error("Join group timeout")), 5000);
244
- }));
245
- it("should broadcast messages to group members", async ()=>new Promise((resolve, reject)=>{
246
- let client1NodeId = null;
247
- let broadcastGroupId = null;
248
- const client1 = new GatewayClient(`ws://localhost:${port}/ws`, "broadcaster", {
249
- events: {
250
- registered: async (nodeId)=>{
251
- client1NodeId = nodeId;
252
- await client1.joinGroup("broadcast-test");
253
- },
254
- joinedGroup: (groupId)=>{
255
- broadcastGroupId = groupId;
256
- client2.connect().catch(reject);
257
- }
258
- }
259
- });
260
- const client2 = new GatewayClient(`ws://localhost:${port}/ws`, "receiver", {
261
- events: {
262
- registered: async ()=>{
263
- await client2.joinGroup("broadcast-test");
264
- },
265
- joinedGroup: ()=>{
266
- client1.broadcast(broadcastGroupId || "broadcast-test", {
267
- message: "Hello from client 1"
268
- });
269
- },
270
- broadcast: (message, fromNodeId)=>{
271
- expect(fromNodeId).toBe(client1NodeId);
272
- expect(message.message).toBe("Hello from client 1");
273
- client1.disconnect();
274
- client2.disconnect();
275
- resolve();
276
- },
277
- error: (error)=>{
278
- reject(new Error(error.message));
279
- }
280
- }
281
- });
282
- client1.connect().catch(reject);
283
- setTimeout(()=>reject(new Error("Broadcast test timeout")), 10000);
284
- }));
285
- it("should handle ping/pong", async ()=>new Promise((resolve, reject)=>{
286
- const client = new GatewayClient(`ws://localhost:${port}/ws`, "ping-test", {
287
- events: {
288
- registered: ()=>{
289
- client.ping();
290
- },
291
- pong: ()=>{
292
- client.disconnect();
293
- resolve();
294
- },
295
- error: (error)=>{
296
- reject(new Error(error.message));
297
- }
298
- }
299
- });
300
- client.connect().catch(reject);
301
- setTimeout(()=>reject(new Error("Ping/pong timeout")), 5000);
302
- }));
303
- it("should stream agent events to session subscribers", async ()=>{
304
- const subscriber = await connectClient("session-subscriber");
305
- const sessionId = "session-test";
306
- subscriber.send(JSON.stringify({
307
- type: "session_subscribe",
308
- payload: {
309
- sessionId
310
- },
311
- timestamp: Date.now()
312
- }));
313
- await waitForMessage(subscriber, (msg)=>"ack" === msg.type && msg.payload?.action === "session_subscribe" && msg.payload?.sessionId === sessionId);
314
- const eventPromise = waitForMessage(subscriber, (msg)=>"event:agent" === msg.type && "req-session" === msg.id);
315
- const sent = server.broadcastSessionEvent(sessionId, {
316
- type: "event:agent",
317
- id: "req-session",
318
- payload: {
319
- type: "agent-stream",
320
- sessionId,
321
- agentId: "main",
322
- chunk: {
323
- content: "hello"
324
- }
325
- },
326
- timestamp: Date.now()
327
- });
328
- expect(sent).toBe(1);
329
- const eventMsg = await eventPromise;
330
- expect(eventMsg.payload?.sessionId).toBe(sessionId);
331
- subscriber.close();
332
- });
333
- it("should broadcast user messages to session subscribers", async ()=>{
334
- const subscriber = await connectClient("session-input-subscriber");
335
- const requester = await connectClient("session-input-requester");
336
- const sessionId = "session-input-test";
337
- subscriber.send(JSON.stringify({
338
- type: "session_subscribe",
339
- payload: {
340
- sessionId
341
- },
342
- timestamp: Date.now()
343
- }));
344
- await waitForMessage(subscriber, (msg)=>"ack" === msg.type && msg.payload?.action === "session_subscribe" && msg.payload?.sessionId === sessionId);
345
- const eventPromise = waitForMessage(subscriber, (msg)=>"event:agent" === msg.type && msg.payload?.type === "session-message" && msg.payload?.role === "user");
346
- requester.send(JSON.stringify({
347
- type: "req:agent",
348
- id: "req-session-input",
349
- payload: {
350
- agentId: "main",
351
- sessionKey: sessionId,
352
- content: "Hello from test"
353
- },
354
- timestamp: Date.now()
355
- }));
356
- const eventMsg = await eventPromise;
357
- expect(eventMsg.payload?.content).toBe("Hello from test");
358
- expect(eventMsg.payload?.sessionId).toBe(sessionId);
359
- expect(eventMsg.payload?.agentId).toBe("main");
360
- subscriber.close();
361
- requester.close();
362
- });
363
- it("should broadcast user messages to webui clients without session subscribe", async ()=>{
364
- const webuiClient = await connectClient("session-webui-listener", "webui");
365
- const requester = await connectClient("session-webui-requester");
366
- const sessionId = "session-webui-test";
367
- const eventPromise = waitForMessage(webuiClient, (msg)=>"event:agent" === msg.type && msg.payload?.type === "session-message" && msg.payload?.role === "user" && msg.payload?.sessionId === sessionId);
368
- requester.send(JSON.stringify({
369
- type: "req:agent",
370
- id: "req-session-webui",
371
- payload: {
372
- agentId: "main",
373
- sessionKey: sessionId,
374
- content: "Hello webui"
375
- },
376
- timestamp: Date.now()
377
- }));
378
- const eventMsg = await eventPromise;
379
- expect(eventMsg.payload?.content).toBe("Hello webui");
380
- expect(eventMsg.payload?.agentId).toBe("main");
381
- webuiClient.close();
382
- requester.close();
383
- });
384
- it("should broadcast user messages to desktop clients without session subscribe", async ()=>{
385
- const desktopClient = await connectClient("session-desktop-listener", "desktop");
386
- const requester = await connectClient("session-desktop-requester");
387
- const sessionId = "session-desktop-test";
388
- const eventPromise = waitForMessage(desktopClient, (msg)=>"event:agent" === msg.type && msg.payload?.type === "session-message" && msg.payload?.role === "user" && msg.payload?.sessionId === sessionId);
389
- requester.send(JSON.stringify({
390
- type: "req:agent",
391
- id: "req-session-desktop",
392
- payload: {
393
- agentId: "main",
394
- sessionKey: sessionId,
395
- content: "Hello desktop"
396
- },
397
- timestamp: Date.now()
398
- }));
399
- const eventMsg = await eventPromise;
400
- expect(eventMsg.payload?.content).toBe("Hello desktop");
401
- expect(eventMsg.payload?.agentId).toBe("main");
402
- desktopClient.close();
403
- requester.close();
404
- });
405
- it("should emit agent-error to requester when invocation throws without emitting", async ()=>{
406
- const requester = await connectClient("session-error-requester");
407
- const requestId = "req-invocation-error";
408
- const sessionId = "session-error-test";
409
- requester.send(JSON.stringify({
410
- type: "req:agent",
411
- id: requestId,
412
- payload: {
413
- agentId: "main",
414
- sessionKey: sessionId,
415
- content: "throw-no-event"
416
- },
417
- timestamp: Date.now()
418
- }));
419
- const errorMsg = await waitForMessage(requester, (msg)=>"event:agent" === msg.type && msg.id === requestId && msg.payload?.type === "agent-error");
420
- expect(errorMsg.payload?.error).toContain("Synthetic invocation failure");
421
- expect(errorMsg.payload?.sessionId).toBe(sessionId);
422
- expect(errorMsg.payload?.agentId).toBe("main");
423
- requester.close();
424
- });
425
- it("should emit agent-complete when invocation returns without terminal output events", async ()=>{
426
- const requester = await connectClient("session-complete-fallback-requester");
427
- const requestId = "req-complete-fallback";
428
- const sessionId = "session-complete-fallback";
429
- requester.send(JSON.stringify({
430
- type: "req:agent",
431
- id: requestId,
432
- payload: {
433
- agentId: "main",
434
- sessionKey: sessionId,
435
- content: "return-no-event"
436
- },
437
- timestamp: Date.now()
438
- }));
439
- const completeMsg = await waitForMessage(requester, (msg)=>"event:agent" === msg.type && msg.id === requestId && msg.payload?.type === "agent-complete");
440
- expect(completeMsg.payload?.sessionId).toBe(sessionId);
441
- expect(completeMsg.payload?.agentId).toBe("main");
442
- expect(completeMsg.payload?.result).toEqual({
443
- streaming: true
444
- });
445
- requester.close();
446
- });
447
- it("does not auto-convert streamed model failure text into agent-error", async ()=>{
448
- const requester = await connectClient("session-streamed-failure-requester");
449
- const requestId = "req-streamed-failure-no-error";
450
- const sessionId = "session-streamed-failure-no-error";
451
- requester.send(JSON.stringify({
452
- type: "req:agent",
453
- id: requestId,
454
- payload: {
455
- agentId: "main",
456
- sessionKey: sessionId,
457
- content: "stream-model-failure-no-error"
458
- },
459
- timestamp: Date.now()
460
- }));
461
- 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);
462
- expect(JSON.stringify(streamMsg.payload?.chunk?.data || {})).toContain("Model call failed after 3 attempts");
463
- const completeMsg = await waitForMessage(requester, (msg)=>"event:agent" === msg.type && msg.id === requestId && msg.payload?.type === "agent-complete", 10000);
464
- expect(completeMsg.payload?.sessionId).toBe(sessionId);
465
- expect(completeMsg.payload?.agentId).toBe("main");
466
- const terminalErrorEvents = await collectMessages(requester, (msg)=>"event:agent" === msg.type && msg.id === requestId && msg.payload?.type === "agent-error", 400);
467
- expect(terminalErrorEvents).toHaveLength(0);
468
- requester.close();
469
- });
470
- it("should emit a single agent-complete terminal event per request", async ()=>{
471
- const requester = await connectClient("session-single-complete-requester");
472
- const requestId = "req-single-complete";
473
- const sessionId = "session-single-complete";
474
- const completionEventsPromise = collectMessages(requester, (msg)=>"event:agent" === msg.type && msg.id === requestId && msg.payload?.type === "agent-complete", 1000);
475
- requester.send(JSON.stringify({
476
- type: "req:agent",
477
- id: requestId,
478
- payload: {
479
- agentId: "main",
480
- sessionKey: sessionId,
481
- content: "single-complete"
482
- },
483
- timestamp: Date.now()
484
- }));
485
- const completionEvents = await completionEventsPromise;
486
- expect(completionEvents).toHaveLength(1);
487
- expect(completionEvents[0].payload?.sessionId).toBe(sessionId);
488
- expect(completionEvents[0].payload?.agentId).toBe("main");
489
- requester.close();
490
- });
491
- it("uses request execution workspace/configDir overrides for agent invocation", async ()=>{
492
- const requester = await connectClient("session-workspace-override-requester");
493
- const requestId = "req-workspace-override";
494
- const sessionId = "session-workspace-override";
495
- const workspaceOverride = "/tmp/wingman-override-workspace";
496
- const configDirOverride = ".wingman-custom";
497
- const beforeCount = invokerConstructOptions.length;
498
- requester.send(JSON.stringify({
499
- type: "req:agent",
500
- id: requestId,
501
- payload: {
502
- agentId: "main",
503
- sessionKey: sessionId,
504
- content: "workspace override test",
505
- execution: {
506
- workspace: workspaceOverride,
507
- configDir: configDirOverride
508
- }
509
- },
510
- timestamp: Date.now()
511
- }));
512
- await waitForMessage(requester, (msg)=>"event:agent" === msg.type && msg.id === requestId && msg.payload?.type === "agent-complete", 10000);
513
- expect(invokerConstructOptions.length).toBeGreaterThan(beforeCount);
514
- const lastOptions = invokerConstructOptions.at(-1) || {};
515
- expect(lastOptions.workspace).toBe(workspaceOverride);
516
- expect(lastOptions.configDir).toBe(configDirOverride);
517
- expect(typeof lastOptions.nodeInvoker).toBe("function");
518
- requester.close();
519
- });
520
- it("should cancel an in-flight agent request", async ()=>{
521
- const requester = await connectClient("session-cancel-requester");
522
- const requestId = "req-cancel-test";
523
- requester.send(JSON.stringify({
524
- type: "req:agent",
525
- id: requestId,
526
- payload: {
527
- agentId: "main",
528
- sessionKey: "session-cancel-test",
529
- content: "cancel me"
530
- },
531
- timestamp: Date.now()
532
- }));
533
- requester.send(JSON.stringify({
534
- type: "req:agent:cancel",
535
- id: "cancel-req-cancel-test",
536
- payload: {
537
- requestId
538
- },
539
- timestamp: Date.now()
540
- }));
541
- const ack = await waitForMessage(requester, (msg)=>"ack" === msg.type && msg.payload?.action === "req:agent:cancel" && msg.payload?.requestId === requestId);
542
- expect([
543
- "cancelled",
544
- "not_found"
545
- ]).toContain(ack.payload?.status);
546
- requester.close();
547
- });
548
- it("should queue and dequeue requests for the same session", async ()=>{
549
- const requester = await connectClient("session-queue-requester");
550
- const sessionId = `session-queue-${Date.now()}`;
551
- const firstRequestId = `req-queue-first-${Date.now()}`;
552
- const secondRequestId = `req-queue-second-${Date.now()}`;
553
- const firstCompletePromise = waitForMessage(requester, (msg)=>"event:agent" === msg.type && msg.id === firstRequestId && msg.payload?.type === "agent-complete", 10000);
554
- const queuedAckPromise = waitForMessage(requester, (msg)=>"ack" === msg.type && msg.id === secondRequestId && msg.payload?.action === "req:agent" && msg.payload?.status === "queued", 10000);
555
- const queuedEventPromise = waitForMessage(requester, (msg)=>"event:agent" === msg.type && msg.id === secondRequestId && msg.payload?.type === "request-queued", 10000);
556
- const dequeuedAckPromise = waitForMessage(requester, (msg)=>"ack" === msg.type && msg.id === secondRequestId && msg.payload?.action === "req:agent" && msg.payload?.status === "dequeued", 10000);
557
- const secondCompletePromise = waitForMessage(requester, (msg)=>"event:agent" === msg.type && msg.id === secondRequestId && msg.payload?.type === "agent-complete", 10000);
558
- requester.send(JSON.stringify({
559
- type: "req:agent",
560
- id: firstRequestId,
561
- payload: {
562
- agentId: "main",
563
- sessionKey: sessionId,
564
- content: "First queued request"
565
- },
566
- timestamp: Date.now()
567
- }));
568
- requester.send(JSON.stringify({
569
- type: "req:agent",
570
- id: secondRequestId,
571
- payload: {
572
- agentId: "main",
573
- sessionKey: sessionId,
574
- content: "Second queued request"
575
- },
576
- timestamp: Date.now()
577
- }));
578
- const queuedAck = await queuedAckPromise;
579
- expect(queuedAck.payload?.position).toBe(1);
580
- const queuedEvent = await queuedEventPromise;
581
- expect(queuedEvent.payload?.position).toBe(1);
582
- expect(queuedEvent.payload?.sessionId).toBe(sessionId);
583
- await firstCompletePromise;
584
- const dequeuedAck = await dequeuedAckPromise;
585
- expect(dequeuedAck.payload?.remaining).toBe(0);
586
- await secondCompletePromise;
587
- requester.close();
588
- });
589
- it("should cancel a queued request", async ()=>{
590
- const requester = await connectClient("session-cancel-queued-requester");
591
- const sessionId = `session-cancel-queued-${Date.now()}`;
592
- const firstRequestId = `req-cancel-queued-first-${Date.now()}`;
593
- const secondRequestId = `req-cancel-queued-second-${Date.now()}`;
594
- const queuedAckPromise = waitForMessage(requester, (msg)=>"ack" === msg.type && msg.id === secondRequestId && msg.payload?.action === "req:agent" && msg.payload?.status === "queued", 10000);
595
- requester.send(JSON.stringify({
596
- type: "req:agent",
597
- id: firstRequestId,
598
- payload: {
599
- agentId: "main",
600
- sessionKey: sessionId,
601
- content: "First request"
602
- },
603
- timestamp: Date.now()
604
- }));
605
- requester.send(JSON.stringify({
606
- type: "req:agent",
607
- id: secondRequestId,
608
- payload: {
609
- agentId: "main",
610
- sessionKey: sessionId,
611
- content: "Second request"
612
- },
613
- timestamp: Date.now()
614
- }));
615
- await queuedAckPromise;
616
- requester.send(JSON.stringify({
617
- type: "req:agent:cancel",
618
- id: `cancel-${secondRequestId}`,
619
- payload: {
620
- requestId: secondRequestId
621
- },
622
- timestamp: Date.now()
623
- }));
624
- const cancelAck = await waitForMessage(requester, (msg)=>"ack" === msg.type && msg.payload?.action === "req:agent:cancel" && msg.payload?.requestId === secondRequestId && msg.payload?.status === "cancelled_queued", 10000);
625
- expect(cancelAck.payload?.status).toBe("cancelled_queued");
626
- const cancelEvent = await waitForMessage(requester, (msg)=>"event:agent" === msg.type && msg.id === secondRequestId && msg.payload?.type === "agent-error" && /cancel/i.test(String(msg.payload?.error || "")), 10000);
627
- expect(cancelEvent.payload?.sessionId).toBe(sessionId);
628
- expect(cancelEvent.payload?.agentId).toBe("main");
629
- await waitForMessage(requester, (msg)=>"event:agent" === msg.type && msg.id === firstRequestId && msg.payload?.type === "agent-complete", 10000);
630
- const queuedRequests = server.queuedSessionRequests;
631
- const isStillQueued = [
632
- ...queuedRequests.values()
633
- ].some((queue)=>queue.some((item)=>item.msg?.id === secondRequestId));
634
- expect(isStillQueued).toBe(false);
635
- requester.close();
636
- });
637
- it("should clear session messages via API", async ()=>{
638
- const createRes = await fetch(`http://localhost:${port}/api/sessions`, {
639
- method: "POST",
640
- headers: {
641
- "Content-Type": "application/json"
642
- },
643
- body: JSON.stringify({
644
- name: "Clear Test"
645
- })
646
- });
647
- expect(createRes.ok).toBe(true);
648
- const session = await createRes.json();
649
- const sessionAgentId = session.agentId || "main";
650
- const manager = await server.getSessionManager(sessionAgentId);
651
- manager.updateSession(session.id, {
652
- messageCount: 3,
653
- lastMessagePreview: "Hello"
654
- });
655
- const clearRes = await fetch(`http://localhost:${port}/api/sessions/${encodeURIComponent(session.id)}/messages?agentId=${encodeURIComponent(sessionAgentId)}`, {
656
- method: "DELETE"
657
- });
658
- expect(clearRes.ok).toBe(true);
659
- const cleared = await clearRes.json();
660
- expect(cleared.messageCount).toBe(0);
661
- const updated = manager.getSession(session.id);
662
- expect(updated?.messageCount).toBe(0);
663
- expect(updated?.lastMessagePreview).toBeNull();
664
- });
665
- it("persists failed first-turn messages so the thread survives reload", async ()=>{
666
- const requester = await connectClient("persist-failed-turn-requester");
667
- const sessionId = `session-persist-failed-${Date.now()}`;
668
- const requestId = `req-persist-failed-${Date.now()}`;
669
- requester.send(JSON.stringify({
670
- type: "req:agent",
671
- id: requestId,
672
- payload: {
673
- agentId: "main",
674
- sessionKey: sessionId,
675
- content: "throw-no-event"
676
- },
677
- timestamp: Date.now()
678
- }));
679
- await waitForMessage(requester, (msg)=>"event:agent" === msg.type && msg.id === requestId && msg.payload?.type === "agent-error", 10000);
680
- const sessionsRes = await fetch(`http://localhost:${port}/api/sessions?limit=100`);
681
- expect(sessionsRes.ok).toBe(true);
682
- const sessions = await sessionsRes.json();
683
- const created = sessions.find((session)=>session.id === sessionId);
684
- expect(created).toBeTruthy();
685
- expect(created?.messageCount).toBe(1);
686
- const messagesRes = await fetch(`http://localhost:${port}/api/sessions/${encodeURIComponent(sessionId)}/messages?agentId=main`);
687
- expect(messagesRes.ok).toBe(true);
688
- const messages = await messagesRes.json();
689
- expect(messages.some((message)=>"user" === message.role)).toBe(true);
690
- expect(messages.some((message)=>"user" === message.role && message.content.includes("throw-no-event"))).toBe(true);
691
- expect(messages.some((message)=>"assistant" === message.role && message.content.includes("Synthetic invocation failure"))).toBe(true);
692
- requester.close();
693
- });
694
- });