@agent-spaces/server 0.3.65 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (278) hide show
  1. package/dist/adapters/agent-runtime.js +8 -0
  2. package/dist/adapters/codex-function-tool-bridge.js +152 -0
  3. package/dist/adapters/codex-runtime.js +23 -4
  4. package/dist/adapters/git.js +25 -3
  5. package/dist/adapters/hermes-runtime.js +813 -0
  6. package/dist/adapters/langchain-runtime.js +384 -21
  7. package/dist/adapters/oh-my-pi-runtime.js +858 -0
  8. package/dist/adapters/open-agent-sdk-runtime.js +202 -5
  9. package/dist/adapters/open-agent-sdk-runtime.test.js +35 -0
  10. package/dist/agents/agent-message-parts.js +52 -2
  11. package/dist/agents/issue-task-controller.js +71 -2
  12. package/dist/agents/pull-request-agent.js +115 -0
  13. package/dist/agents/scheduler-agent.js +1 -1
  14. package/dist/agents/title-generator-agent.js +120 -0
  15. package/dist/app.js +61 -4
  16. package/dist/middleware/auth.js +1 -1
  17. package/dist/package.json +2 -1
  18. package/dist/routes/agent-sse.js +70 -6
  19. package/dist/routes/channel.js +23 -2
  20. package/dist/routes/chat-run.js +191 -0
  21. package/dist/routes/chat.js +142 -0
  22. package/dist/routes/command.js +16 -0
  23. package/dist/routes/data.js +189 -0
  24. package/dist/routes/git.js +10 -1
  25. package/dist/routes/import.js +199 -0
  26. package/dist/routes/issue.js +17 -5
  27. package/dist/routes/notification.js +10 -0
  28. package/dist/routes/plugin.js +69 -0
  29. package/dist/routes/version.js +95 -0
  30. package/dist/routes/workflow-hook.js +71 -0
  31. package/dist/routes/workflow.js +282 -7
  32. package/dist/routes/workspace.js +13 -4
  33. package/dist/routes/worktree.js +93 -0
  34. package/dist/services/agent.js +123 -36
  35. package/dist/services/ai-text.js +185 -0
  36. package/dist/services/builtin-tools/index.js +1 -0
  37. package/dist/services/builtin-tools/workflow-editor-tools.js +509 -0
  38. package/dist/services/builtin-tools/workflow-exec-tools.js +320 -0
  39. package/dist/services/chat.js +134 -0
  40. package/dist/services/command-process-manager.js +16 -0
  41. package/dist/services/execution-manager.js +1346 -0
  42. package/dist/services/generated-title.js +59 -0
  43. package/dist/services/gitignore.js +22 -18
  44. package/dist/services/interaction-manager.js +114 -0
  45. package/dist/services/issue-retry.js +25 -0
  46. package/dist/services/notification-center.js +9 -0
  47. package/dist/services/output-style.js +8 -1
  48. package/dist/services/plugin.js +257 -0
  49. package/dist/services/prompt-template.js +8 -1
  50. package/dist/services/pty.js +20 -0
  51. package/dist/services/search.js +16 -6
  52. package/dist/services/skill.js +2 -0
  53. package/dist/services/version.js +69 -0
  54. package/dist/services/workflow-command-runner.js +24 -0
  55. package/dist/services/workflow-trigger-service.js +137 -0
  56. package/dist/services/workflow.js +219 -39
  57. package/dist/services/workspace.js +23 -1
  58. package/dist/services/worktree.js +207 -0
  59. package/dist/storage/agent-store.js +8 -0
  60. package/dist/storage/chat-store.js +151 -0
  61. package/dist/storage/database-store.js +6 -0
  62. package/dist/storage/json-store.js +2 -1
  63. package/dist/storage/kanban-store.js +6 -0
  64. package/dist/storage/workflow-store.js +386 -22
  65. package/dist/storage/worktree-store.js +33 -0
  66. package/dist/web/404.html +1 -1
  67. package/dist/web/__next.__PAGE__.txt +4 -4
  68. package/dist/web/__next._full.txt +21 -21
  69. package/dist/web/__next._head.txt +4 -4
  70. package/dist/web/__next._index.txt +13 -13
  71. package/dist/web/__next._tree.txt +2 -2
  72. package/dist/web/_next/static/chunks/{08x85faoz58i7.js → 0-92u-tiuy40a.js} +4 -4
  73. package/dist/web/_next/static/chunks/{0db14450oqzhg.js → 0-yizd8osmas2.js} +1 -1
  74. package/dist/web/_next/static/chunks/0.ln~3mnv8.69.js +1 -0
  75. package/dist/web/_next/static/chunks/{11cchuwoupmbf.js → 01y3e9pemva7b.js} +10 -10
  76. package/dist/web/_next/static/chunks/02l~tmzrgny.~.js +1 -0
  77. package/dist/web/_next/static/chunks/03f1bwuynjdmk.js +1 -0
  78. package/dist/web/_next/static/chunks/04cb4kc9r2pd1.js +1 -0
  79. package/dist/web/_next/static/chunks/04de6ha5_e3pp.js +1 -0
  80. package/dist/web/_next/static/chunks/09he0p79ov1rn.js +1 -0
  81. package/dist/web/_next/static/chunks/09vpocs4zuc8h.js +1 -0
  82. package/dist/web/_next/static/chunks/0_o2exgr0e_nh.js +1 -0
  83. package/dist/web/_next/static/chunks/{0xbaakj0dfc0..js → 0_y9nskc-xt2k.js} +1 -1
  84. package/dist/web/_next/static/chunks/0clnj-1fi6u8j.js +3 -0
  85. package/dist/web/_next/static/chunks/0gv40by0zzxs_.js +1 -0
  86. package/dist/web/_next/static/chunks/0iusr8y88.kjg.js +1 -0
  87. package/dist/web/_next/static/chunks/{0-a.-hl3wv99k.js → 0j-8418fxvkd1.js} +1 -1
  88. package/dist/web/_next/static/chunks/0j.wxxyoclma5.js +1 -0
  89. package/dist/web/_next/static/chunks/{0.6b64sy0g5.3.js → 0jq.16sozqik..js} +1 -1
  90. package/dist/web/_next/static/chunks/0jw8xdk_fpnp0.css +1 -0
  91. package/dist/web/_next/static/chunks/0l1lkd-wcotma.js +1 -0
  92. package/dist/web/_next/static/chunks/{0u6h-hqc_i52e.js → 0ncxf_zr4n839.js} +1 -1
  93. package/dist/web/_next/static/chunks/0ndo7um~v7vco.js +1 -0
  94. package/dist/web/_next/static/chunks/0ngk.~kan8wq_.js +1 -0
  95. package/dist/web/_next/static/chunks/0ppr271hz0xoq.js +1 -0
  96. package/dist/web/_next/static/chunks/0rt9bofnn6qvn.js +1 -0
  97. package/dist/web/_next/static/chunks/0t64.9jd00hio.js +3 -0
  98. package/dist/web/_next/static/chunks/0taui9--5n6-5.js +1 -0
  99. package/dist/web/_next/static/chunks/0ty39169lh~z3.js +1 -0
  100. package/dist/web/_next/static/chunks/0v8nof~waedlu.js +1 -0
  101. package/dist/web/_next/static/chunks/{0-pi.67w.ymsr.js → 0vcfoagnpf.aw.js} +1 -1
  102. package/dist/web/_next/static/chunks/{0vis~lx0nxgn-.js → 0wwwq.gyyz0vg.js} +3 -3
  103. package/dist/web/_next/static/chunks/0x5lak8yz7pm7.js +1 -0
  104. package/dist/web/_next/static/chunks/0xon_.4-o0_zq.js +7 -0
  105. package/dist/web/_next/static/chunks/0zjnrbt7inime.js +1 -0
  106. package/dist/web/_next/static/chunks/0zwebpitvpuv1.js +1 -0
  107. package/dist/web/_next/static/chunks/0~02o4g-o6n~m.js +1 -0
  108. package/dist/web/_next/static/chunks/{0w7.tb29958zj.js → 0~fjezp.k4qk3.js} +1 -1
  109. package/dist/web/_next/static/chunks/0~sh93re1-_rp.js +1 -0
  110. package/dist/web/_next/static/chunks/10_niiq0k6o-p.js +5 -0
  111. package/dist/web/_next/static/chunks/12tjr0_2ccrtq.js +2 -0
  112. package/dist/web/_next/static/chunks/12x5.go_x9mfk.js +1 -0
  113. package/dist/web/_next/static/chunks/{0l2w0qz1ea7ql.js → 12~5dk9i9d16t.js} +2 -2
  114. package/dist/web/_next/static/chunks/13iye4rv5p31b.js +1 -0
  115. package/dist/web/_next/static/chunks/{01~quun6sefgl.js → 13~y-b.b9rrw4.js} +1 -1
  116. package/dist/web/_next/static/chunks/151wzhb5q0lo5.js +1 -0
  117. package/dist/web/_not-found/__next._full.txt +19 -19
  118. package/dist/web/_not-found/__next._head.txt +4 -4
  119. package/dist/web/_not-found/__next._index.txt +13 -13
  120. package/dist/web/_not-found/__next._not-found.__PAGE__.txt +2 -2
  121. package/dist/web/_not-found/__next._not-found.txt +3 -3
  122. package/dist/web/_not-found/__next._tree.txt +2 -2
  123. package/dist/web/_not-found.html +1 -1
  124. package/dist/web/_not-found.txt +19 -19
  125. package/dist/web/index.html +1 -1
  126. package/dist/web/index.txt +21 -21
  127. package/dist/web/login/__next._full.txt +21 -21
  128. package/dist/web/login/__next._head.txt +4 -4
  129. package/dist/web/login/__next._index.txt +13 -13
  130. package/dist/web/login/__next._tree.txt +2 -2
  131. package/dist/web/login/__next.login.__PAGE__.txt +4 -4
  132. package/dist/web/login/__next.login.txt +3 -3
  133. package/dist/web/login.html +1 -1
  134. package/dist/web/login.txt +21 -21
  135. package/dist/web/settings/__next._full.txt +23 -23
  136. package/dist/web/settings/__next._head.txt +4 -4
  137. package/dist/web/settings/__next._index.txt +13 -13
  138. package/dist/web/settings/__next._tree.txt +2 -2
  139. package/dist/web/settings/__next.settings.__PAGE__.txt +4 -4
  140. package/dist/web/settings/__next.settings.txt +5 -5
  141. package/dist/web/settings/agents/__next._full.txt +23 -23
  142. package/dist/web/settings/agents/__next._head.txt +4 -4
  143. package/dist/web/settings/agents/__next._index.txt +13 -13
  144. package/dist/web/settings/agents/__next._tree.txt +2 -2
  145. package/dist/web/settings/agents/__next.settings.agents.__PAGE__.txt +4 -4
  146. package/dist/web/settings/agents/__next.settings.agents.txt +3 -3
  147. package/dist/web/settings/agents/__next.settings.txt +5 -5
  148. package/dist/web/settings/agents.html +1 -1
  149. package/dist/web/settings/agents.txt +23 -23
  150. package/dist/web/settings/mcps/__next._full.txt +23 -23
  151. package/dist/web/settings/mcps/__next._head.txt +4 -4
  152. package/dist/web/settings/mcps/__next._index.txt +13 -13
  153. package/dist/web/settings/mcps/__next._tree.txt +2 -2
  154. package/dist/web/settings/mcps/__next.settings.mcps.__PAGE__.txt +4 -4
  155. package/dist/web/settings/mcps/__next.settings.mcps.txt +3 -3
  156. package/dist/web/settings/mcps/__next.settings.txt +5 -5
  157. package/dist/web/settings/mcps.html +1 -1
  158. package/dist/web/settings/mcps.txt +23 -23
  159. package/dist/web/settings/models/__next._full.txt +23 -23
  160. package/dist/web/settings/models/__next._head.txt +4 -4
  161. package/dist/web/settings/models/__next._index.txt +13 -13
  162. package/dist/web/settings/models/__next._tree.txt +2 -2
  163. package/dist/web/settings/models/__next.settings.models.__PAGE__.txt +4 -4
  164. package/dist/web/settings/models/__next.settings.models.txt +3 -3
  165. package/dist/web/settings/models/__next.settings.txt +5 -5
  166. package/dist/web/settings/models.html +1 -1
  167. package/dist/web/settings/models.txt +23 -23
  168. package/dist/web/settings/output-styles/__next._full.txt +23 -23
  169. package/dist/web/settings/output-styles/__next._head.txt +4 -4
  170. package/dist/web/settings/output-styles/__next._index.txt +13 -13
  171. package/dist/web/settings/output-styles/__next._tree.txt +2 -2
  172. package/dist/web/settings/output-styles/__next.settings.output-styles.__PAGE__.txt +4 -4
  173. package/dist/web/settings/output-styles/__next.settings.output-styles.txt +3 -3
  174. package/dist/web/settings/output-styles/__next.settings.txt +5 -5
  175. package/dist/web/settings/output-styles.html +1 -1
  176. package/dist/web/settings/output-styles.txt +23 -23
  177. package/dist/web/settings/prompts/__next._full.txt +23 -23
  178. package/dist/web/settings/prompts/__next._head.txt +4 -4
  179. package/dist/web/settings/prompts/__next._index.txt +13 -13
  180. package/dist/web/settings/prompts/__next._tree.txt +2 -2
  181. package/dist/web/settings/prompts/__next.settings.prompts.__PAGE__.txt +4 -4
  182. package/dist/web/settings/prompts/__next.settings.prompts.txt +3 -3
  183. package/dist/web/settings/prompts/__next.settings.txt +5 -5
  184. package/dist/web/settings/prompts.html +1 -1
  185. package/dist/web/settings/prompts.txt +23 -23
  186. package/dist/web/settings/providers/__next._full.txt +23 -23
  187. package/dist/web/settings/providers/__next._head.txt +4 -4
  188. package/dist/web/settings/providers/__next._index.txt +13 -13
  189. package/dist/web/settings/providers/__next._tree.txt +2 -2
  190. package/dist/web/settings/providers/__next.settings.providers.__PAGE__.txt +4 -4
  191. package/dist/web/settings/providers/__next.settings.providers.txt +3 -3
  192. package/dist/web/settings/providers/__next.settings.txt +5 -5
  193. package/dist/web/settings/providers.html +1 -1
  194. package/dist/web/settings/providers.txt +23 -23
  195. package/dist/web/settings/skills/__next._full.txt +23 -23
  196. package/dist/web/settings/skills/__next._head.txt +4 -4
  197. package/dist/web/settings/skills/__next._index.txt +13 -13
  198. package/dist/web/settings/skills/__next._tree.txt +2 -2
  199. package/dist/web/settings/skills/__next.settings.skills.__PAGE__.txt +4 -4
  200. package/dist/web/settings/skills/__next.settings.skills.txt +3 -3
  201. package/dist/web/settings/skills/__next.settings.txt +5 -5
  202. package/dist/web/settings/skills.html +1 -1
  203. package/dist/web/settings/skills.txt +23 -23
  204. package/dist/web/settings/tools/__next._full.txt +23 -23
  205. package/dist/web/settings/tools/__next._head.txt +4 -4
  206. package/dist/web/settings/tools/__next._index.txt +13 -13
  207. package/dist/web/settings/tools/__next._tree.txt +2 -2
  208. package/dist/web/settings/tools/__next.settings.tools.__PAGE__.txt +4 -4
  209. package/dist/web/settings/tools/__next.settings.tools.txt +3 -3
  210. package/dist/web/settings/tools/__next.settings.txt +5 -5
  211. package/dist/web/settings/tools.html +1 -1
  212. package/dist/web/settings/tools.txt +23 -23
  213. package/dist/web/settings.html +1 -1
  214. package/dist/web/settings.txt +23 -23
  215. package/dist/web/workflows/__next._full.txt +22 -22
  216. package/dist/web/workflows/__next._head.txt +4 -4
  217. package/dist/web/workflows/__next._index.txt +13 -13
  218. package/dist/web/workflows/__next._tree.txt +2 -2
  219. package/dist/web/workflows/__next.workflows.__PAGE__.txt +4 -4
  220. package/dist/web/workflows/__next.workflows.txt +3 -3
  221. package/dist/web/workflows.html +1 -1
  222. package/dist/web/workflows.txt +22 -22
  223. package/dist/web/workspace/_/__next._full.txt +20 -20
  224. package/dist/web/workspace/_/__next._head.txt +4 -4
  225. package/dist/web/workspace/_/__next._index.txt +13 -13
  226. package/dist/web/workspace/_/__next._tree.txt +2 -2
  227. package/dist/web/workspace/_/__next.workspace.$d$id.__PAGE__.txt +3 -3
  228. package/dist/web/workspace/_/__next.workspace.$d$id.txt +3 -3
  229. package/dist/web/workspace/_/__next.workspace.txt +3 -3
  230. package/dist/web/workspace/_.html +1 -1
  231. package/dist/web/workspace/_.txt +20 -20
  232. package/dist/web/workspaces/__next._full.txt +21 -21
  233. package/dist/web/workspaces/__next._head.txt +4 -4
  234. package/dist/web/workspaces/__next._index.txt +13 -13
  235. package/dist/web/workspaces/__next._tree.txt +2 -2
  236. package/dist/web/workspaces/__next.workspaces.__PAGE__.txt +4 -4
  237. package/dist/web/workspaces/__next.workspaces.txt +3 -3
  238. package/dist/web/workspaces.html +1 -1
  239. package/dist/web/workspaces.txt +21 -21
  240. package/dist/ws/agent-prompt.js +36 -3
  241. package/dist/ws/agent-runner.js +30 -18
  242. package/dist/ws/chat-handler.js +89 -0
  243. package/dist/ws/connection-manager.js +49 -2
  244. package/dist/ws/execution-channels.js +88 -0
  245. package/dist/ws/handler.js +32 -5
  246. package/dist/ws/message-parts.js +130 -12
  247. package/dist/ws/terminal-handler.js +26 -0
  248. package/package.json +13 -1
  249. package/public/avatars/user.jpg +0 -0
  250. package/dist/web/_next/static/chunks/0-v_p6j5u3_9l.js +0 -1
  251. package/dist/web/_next/static/chunks/0.-x29t-8gk0r.js +0 -1
  252. package/dist/web/_next/static/chunks/0.l5e8~r7_0~p.js +0 -1
  253. package/dist/web/_next/static/chunks/0.n~yfwf4~6w-.js +0 -1
  254. package/dist/web/_next/static/chunks/00-syqzi-6zxr.js +0 -1
  255. package/dist/web/_next/static/chunks/02j4sr9psucf-.js +0 -1
  256. package/dist/web/_next/static/chunks/06si8l0doqe8p.js +0 -1
  257. package/dist/web/_next/static/chunks/08kfx8on9oty~.js +0 -1
  258. package/dist/web/_next/static/chunks/08ugbvzr20drp.js +0 -2
  259. package/dist/web/_next/static/chunks/0_cqojbge48kq.js +0 -5
  260. package/dist/web/_next/static/chunks/0d6~~lv0-6kex.js +0 -3
  261. package/dist/web/_next/static/chunks/0gdwop9cnpmtu.js +0 -1
  262. package/dist/web/_next/static/chunks/0ghx3j_.-gdyd.js +0 -1
  263. package/dist/web/_next/static/chunks/0kbvoxla7f751.js +0 -1
  264. package/dist/web/_next/static/chunks/0paaat8y96ayc.js +0 -7
  265. package/dist/web/_next/static/chunks/0pq318f8xgafg.js +0 -1
  266. package/dist/web/_next/static/chunks/0t6s8of0qr6nc.js +0 -1
  267. package/dist/web/_next/static/chunks/0xt-8wk21gs7g.js +0 -1
  268. package/dist/web/_next/static/chunks/0yd.m1afqg.2t.js +0 -3
  269. package/dist/web/_next/static/chunks/0yhbr8hl09b-5.js +0 -1
  270. package/dist/web/_next/static/chunks/0z~vqzbm_q371.js +0 -1
  271. package/dist/web/_next/static/chunks/0~~_ltu6dx_ch.js +0 -1
  272. package/dist/web/_next/static/chunks/12oxcgyhpaxw~.js +0 -1
  273. package/dist/web/_next/static/chunks/1452eibz62gs6.css +0 -1
  274. package/dist/web/_next/static/chunks/16zlreiems5cn.js +0 -1
  275. package/dist/web/_next/static/chunks/18awqjk9-o5m0.js +0 -1
  276. /package/dist/web/_next/static/{x4-CsKe6qUQyFDWVtfvUg → rGXyAK8rgod1NjF3bLZAY}/_buildManifest.js +0 -0
  277. /package/dist/web/_next/static/{x4-CsKe6qUQyFDWVtfvUg → rGXyAK8rgod1NjF3bLZAY}/_clientMiddlewareManifest.js +0 -0
  278. /package/dist/web/_next/static/{x4-CsKe6qUQyFDWVtfvUg → rGXyAK8rgod1NjF3bLZAY}/_ssgManifest.js +0 -0
@@ -4,7 +4,7 @@ import { broadcastToWorkspace } from './connection-manager.js';
4
4
  import { createMessage, updateMessage, listMessages } from '../services/message.js';
5
5
  import { getChannel, updateChannel } from '../services/channel.js';
6
6
  import * as issueService from '../services/issue.js';
7
- import { createIssueFunctionTools, createCommandFunctionTools, createDatabaseFunctionTools, createKanbanFunctionTools } from '../services/builtin-tools/index.js';
7
+ import { createIssueFunctionTools, createCommandFunctionTools, createDatabaseFunctionTools, createKanbanFunctionTools, createWorkflowExecutionFunctionTools } from '../services/builtin-tools/index.js';
8
8
  import { startScheduler } from '../agents/scheduler-agent.js';
9
9
  import * as agentService from '../services/agent.js';
10
10
  import * as wsService from '../services/workspace.js';
@@ -57,17 +57,17 @@ export function stopChannelRuns(workspaceId, channelId) {
57
57
  agentId: run.agentId,
58
58
  error: 'Stopped by user',
59
59
  });
60
+ const existing = listMessages(workspaceId, channelId).find((m) => m.id === run.messageId);
61
+ const preservedParts = (existing?.parts ?? []).map((part) => 'status' in part && part.status === 'streaming' ? { ...part, status: 'completed' } : part);
62
+ const stoppedPart = {
63
+ id: `error-stopped-${run.agentId}`,
64
+ type: 'error',
65
+ title: 'Stopped by user',
66
+ message: 'The agent run was stopped by user.',
67
+ };
60
68
  const message = updateMessage(workspaceId, channelId, run.messageId, {
61
- content: 'Stopped by user',
62
69
  status: 'error',
63
- parts: [
64
- {
65
- id: `terminal-stopped-${run.agentId}`,
66
- type: 'terminal',
67
- output: 'Stopped by user',
68
- status: 'error',
69
- },
70
- ],
70
+ parts: [...preservedParts, stoppedPart],
71
71
  });
72
72
  if (message)
73
73
  broadcastToWorkspace(workspaceId, 'channel.message.updated', message);
@@ -170,10 +170,12 @@ export async function runMentionedAgent(workspaceId, channelId, agentConfigId, p
170
170
  ...createCommandFunctionTools(workspaceId, preset.tools),
171
171
  ...createDatabaseFunctionTools(workspaceId, preset.tools),
172
172
  ...createKanbanFunctionTools(workspaceId, preset.tools),
173
+ ...createWorkflowExecutionFunctionTools(preset.tools),
173
174
  ];
174
175
  const workingDir = agentService.resolveWorkingDir(workspaceId, preset);
175
176
  const startTime = Date.now();
176
177
  const runtimePromptConfig = {
178
+ runtimeKind: preset.runtimeKind,
177
179
  mcpServers: Object.keys(mcpServers ?? {}),
178
180
  skills,
179
181
  boundDirs: workspace?.boundDirs,
@@ -222,7 +224,10 @@ export async function runMentionedAgent(workspaceId, channelId, agentConfigId, p
222
224
  const liveReasoning = [];
223
225
  let agentPrompt = '';
224
226
  let runtimeUserPrompt = prompt;
225
- let runtimeSessionId = options.resumeSessionId ?? existingMessage?.metadata?.runtimeSessionId;
227
+ const contextLength = normalizeContextLength(options.contextLength);
228
+ let runtimeSessionId = contextLength === 0
229
+ ? undefined
230
+ : options.resumeSessionId ?? existingMessage?.metadata?.runtimeSessionId;
226
231
  const persistentContext = buildPersistentAgentContextDetails({
227
232
  workspaceId,
228
233
  workingDir: workspace?.boundDirs?.[0] || workingDir,
@@ -246,13 +251,15 @@ export async function runMentionedAgent(workspaceId, channelId, agentConfigId, p
246
251
  runtime,
247
252
  };
248
253
  trackChannelRun(workspaceId, channelId, activeRun);
249
- const history = filterPromptHistory(listMessages(workspaceId, channelId, { limit: 20 }), {
250
- excludeMessageIds: [
251
- ...(!existingMessage ? [pending.id] : []),
252
- ...(options.excludeHistoryMessageIds ?? []),
253
- ],
254
- excludeReplyIds: options.excludeHistoryReplyIds,
255
- });
254
+ const history = contextLength === 0
255
+ ? []
256
+ : filterPromptHistory(listMessages(workspaceId, channelId, { limit: contextLength }), {
257
+ excludeMessageIds: [
258
+ ...(!existingMessage ? [pending.id] : []),
259
+ ...(options.excludeHistoryMessageIds ?? []),
260
+ ],
261
+ excludeReplyIds: options.excludeHistoryReplyIds,
262
+ });
256
263
  const isRuntimeSessionResume = Boolean(options.resumeSessionId && (preset.runtimeKind === 'claude-code' || preset.runtimeKind === 'codex'));
257
264
  runtimeUserPrompt = expandAgentSlashCommandPrompt(prompt, configDir);
258
265
  agentPrompt = isRuntimeSessionResume
@@ -850,4 +857,9 @@ function estimateTextTokens(text) {
850
857
  const words = nonCjkText.match(/[A-Za-z0-9_]+|[^\sA-Za-z0-9_]/g)?.length ?? 0;
851
858
  return Math.max(1, Math.ceil(cjkChars + words * 0.75));
852
859
  }
860
+ function normalizeContextLength(value) {
861
+ if (typeof value !== 'number' || !Number.isFinite(value))
862
+ return 20;
863
+ return Math.min(20, Math.max(0, Math.trunc(value)));
864
+ }
853
865
  //# sourceMappingURL=agent-runner.js.map
@@ -0,0 +1,89 @@
1
+ import { broadcastToWorkspace } from './connection-manager.js';
2
+ import { registerHandler } from './handler.js';
3
+ import * as chatService from '../services/chat.js';
4
+ import { LangChainRuntime } from '../adapters/langchain-runtime.js';
5
+ const activeRuns = new Map();
6
+ export function registerChatHandlers() {
7
+ // chat.message: { agentId, content }
8
+ registerHandler('chat.message', (_ws, workspaceId, data) => {
9
+ const { agentId, content } = data;
10
+ if (!agentId || !content)
11
+ return;
12
+ const agent = chatService.findAgent(agentId);
13
+ if (!agent) {
14
+ broadcastToWorkspace(workspaceId, 'chat.agent.error', { agentId, error: 'Agent not found' });
15
+ return;
16
+ }
17
+ // Save user message
18
+ const userMsg = chatService.saveMessage({ agentId, role: 'user', content });
19
+ broadcastToWorkspace(workspaceId, 'chat.message.saved', userMsg);
20
+ // Build runtime config (fixed langchain)
21
+ const config = {
22
+ kind: 'langchain',
23
+ provider: agent.provider,
24
+ model: agent.model,
25
+ apiKey: agent.apiKey,
26
+ baseURL: agent.baseURL,
27
+ };
28
+ const runtime = new LangChainRuntime(config);
29
+ activeRuns.set(agentId, runtime);
30
+ // Build conversation history from recent messages
31
+ const recent = chatService.getRecentMessages(agentId, 20);
32
+ const historyPrompt = recent
33
+ .slice(0, -1) // exclude the just-saved user message (already in recent)
34
+ .map((m) => `${m.role === 'user' ? 'User' : 'Assistant'}: ${m.content}`)
35
+ .join('\n\n');
36
+ const prompt = historyPrompt ? `${historyPrompt}\n\nUser: ${content}\nAssistant:` : content;
37
+ // Execute with streaming events
38
+ runtime.execute(prompt, process.cwd(), {
39
+ systemPrompt: agent.systemPrompt,
40
+ onEvent: (event) => {
41
+ switch (event.type) {
42
+ case 'output':
43
+ broadcastToWorkspace(workspaceId, 'chat.agent.output', { agentId, chunk: event.line });
44
+ break;
45
+ case 'reasoning':
46
+ broadcastToWorkspace(workspaceId, 'chat.agent.thinking', { agentId, chunk: event.text });
47
+ break;
48
+ case 'tool_use':
49
+ broadcastToWorkspace(workspaceId, 'chat.agent.tool_use', { agentId, name: event.name, input: event.input });
50
+ break;
51
+ case 'tool_result':
52
+ broadcastToWorkspace(workspaceId, 'chat.agent.tool_result', { agentId, name: event.toolUseId, result: event.result });
53
+ break;
54
+ }
55
+ },
56
+ })
57
+ .then((result) => {
58
+ const agentContent = result.output.filter((line) => !line.startsWith('Tool:')).join('\n') || result.summary;
59
+ const agentMsg = chatService.saveMessage({
60
+ agentId,
61
+ role: 'agent',
62
+ content: agentContent,
63
+ usage: result.usage,
64
+ });
65
+ broadcastToWorkspace(workspaceId, 'chat.agent.completed', { agentId, message: agentMsg });
66
+ })
67
+ .catch((err) => {
68
+ broadcastToWorkspace(workspaceId, 'chat.agent.error', {
69
+ agentId,
70
+ error: err instanceof Error ? err.message : String(err),
71
+ });
72
+ })
73
+ .finally(() => {
74
+ activeRuns.delete(agentId);
75
+ });
76
+ });
77
+ // chat.stop: { agentId }
78
+ registerHandler('chat.stop', (_ws, _workspaceId, data) => {
79
+ const { agentId } = data;
80
+ if (!agentId)
81
+ return;
82
+ const runtime = activeRuns.get(agentId);
83
+ if (runtime) {
84
+ runtime.stop();
85
+ activeRuns.delete(agentId);
86
+ }
87
+ });
88
+ }
89
+ //# sourceMappingURL=chat-handler.js.map
@@ -1,12 +1,59 @@
1
+ import { randomUUID } from 'node:crypto';
1
2
  import { publishWorkspaceEvent } from '../services/notification-hub/index.js';
2
3
  const connections = new Map();
4
+ const clientIdIndex = new Map();
5
+ const clientConnectedCallbacks = [];
6
+ const clientDisconnectedCallbacks = [];
7
+ let interactionResponseHandler = null;
3
8
  export function addConnection(ws, workspaceId) {
4
- connections.set(ws, { ws, workspaceId });
5
- ws.on('close', () => connections.delete(ws));
9
+ const clientId = randomUUID();
10
+ const conn = { ws, workspaceId, clientId };
11
+ connections.set(ws, conn);
12
+ clientIdIndex.set(clientId, conn);
13
+ ws.on('close', () => {
14
+ connections.delete(ws);
15
+ clientIdIndex.delete(clientId);
16
+ for (const cb of clientDisconnectedCallbacks)
17
+ cb(clientId);
18
+ });
19
+ for (const cb of clientConnectedCallbacks)
20
+ cb(clientId, ws);
21
+ return clientId;
6
22
  }
7
23
  export function removeConnection(ws) {
24
+ const conn = connections.get(ws);
25
+ if (conn) {
26
+ clientIdIndex.delete(conn.clientId);
27
+ for (const cb of clientDisconnectedCallbacks)
28
+ cb(conn.clientId);
29
+ }
8
30
  connections.delete(ws);
9
31
  }
32
+ export function getClientId(ws) {
33
+ return connections.get(ws)?.clientId;
34
+ }
35
+ export function getConnectionByClientId(clientId) {
36
+ return clientIdIndex.get(clientId);
37
+ }
38
+ export function sendToClient(clientId, data) {
39
+ const conn = clientIdIndex.get(clientId);
40
+ if (!conn || conn.ws.readyState !== 1)
41
+ return false;
42
+ conn.ws.send(JSON.stringify(data));
43
+ return true;
44
+ }
45
+ export function onClientConnected(cb) {
46
+ clientConnectedCallbacks.push(cb);
47
+ }
48
+ export function onClientDisconnected(cb) {
49
+ clientDisconnectedCallbacks.push(cb);
50
+ }
51
+ export function setInteractionResponseHandler(handler) {
52
+ interactionResponseHandler = handler;
53
+ }
54
+ export function handleInteractionResponse(response, clientId) {
55
+ interactionResponseHandler?.(response, clientId);
56
+ }
10
57
  export function getConnectionsByWorkspace(workspaceId) {
11
58
  const result = [];
12
59
  for (const [ws, conn] of connections) {
@@ -0,0 +1,88 @@
1
+ // WS execution channel handlers — register workflow execution control events
2
+ import { getClientId } from './connection-manager.js';
3
+ import { registerHandler } from './handler.js';
4
+ export function registerExecutionChannels(executionManager) {
5
+ registerHandler('workflow:execute', async (ws, _workspaceId, data) => {
6
+ const clientId = getClientId(ws);
7
+ if (!clientId)
8
+ return;
9
+ try {
10
+ const result = await executionManager.execute(data, clientId, (channel, payload) => {
11
+ if (ws.readyState === 1) {
12
+ ws.send(JSON.stringify({ event: channel, data: payload }));
13
+ }
14
+ });
15
+ ws.send(JSON.stringify({
16
+ event: 'workflow:execute:result',
17
+ data: result,
18
+ }));
19
+ }
20
+ catch (err) {
21
+ ws.send(JSON.stringify({
22
+ event: 'workflow:execute:error',
23
+ data: { error: err.message || String(err) },
24
+ }));
25
+ }
26
+ });
27
+ registerHandler('workflow:pause', (ws, _workspaceId, data) => {
28
+ const { executionId } = data;
29
+ if (!executionId)
30
+ return;
31
+ try {
32
+ const result = executionManager.pause(executionId);
33
+ ws.send(JSON.stringify({ event: 'workflow:pause:result', data: result }));
34
+ }
35
+ catch (err) {
36
+ ws.send(JSON.stringify({ event: 'workflow:pause:error', data: { error: err.message } }));
37
+ }
38
+ });
39
+ registerHandler('workflow:resume', async (ws, _workspaceId, data) => {
40
+ const { executionId } = data;
41
+ if (!executionId)
42
+ return;
43
+ try {
44
+ const result = await executionManager.resume(executionId);
45
+ ws.send(JSON.stringify({ event: 'workflow:resume:result', data: result }));
46
+ }
47
+ catch (err) {
48
+ ws.send(JSON.stringify({ event: 'workflow:resume:error', data: { error: err.message } }));
49
+ }
50
+ });
51
+ registerHandler('workflow:stop', (ws, _workspaceId, data) => {
52
+ const { executionId } = data;
53
+ if (!executionId)
54
+ return;
55
+ try {
56
+ const result = executionManager.stop(executionId);
57
+ ws.send(JSON.stringify({ event: 'workflow:stop:result', data: result }));
58
+ }
59
+ catch (err) {
60
+ ws.send(JSON.stringify({ event: 'workflow:stop:error', data: { error: err.message } }));
61
+ }
62
+ });
63
+ registerHandler('workflow:debug-node', async (ws, _workspaceId, data) => {
64
+ const clientId = getClientId(ws);
65
+ if (!clientId)
66
+ return;
67
+ try {
68
+ const result = await executionManager.debugNode(data, clientId);
69
+ ws.send(JSON.stringify({ event: 'workflow:debug-node:result', data: result }));
70
+ }
71
+ catch (err) {
72
+ ws.send(JSON.stringify({ event: 'workflow:debug-node:error', data: { error: err.message } }));
73
+ }
74
+ });
75
+ registerHandler('workflow:get-execution-recovery', (ws, _workspaceId, data) => {
76
+ const clientId = getClientId(ws);
77
+ if (!clientId)
78
+ return;
79
+ try {
80
+ const result = executionManager.getExecutionRecovery(data, clientId);
81
+ ws.send(JSON.stringify({ event: 'workflow:get-execution-recovery:result', data: result }));
82
+ }
83
+ catch (err) {
84
+ ws.send(JSON.stringify({ event: 'workflow:get-execution-recovery:error', data: { error: err.message } }));
85
+ }
86
+ });
87
+ }
88
+ //# sourceMappingURL=execution-channels.js.map
@@ -1,7 +1,9 @@
1
- import { addConnection, broadcastToWorkspace } from './connection-manager.js';
1
+ import { addConnection, broadcastToWorkspace, getClientId, handleInteractionResponse } from './connection-manager.js';
2
2
  import { handleTerminalEvent, sendTerminalSessions } from './terminal-handler.js';
3
+ import { registerChatHandlers } from './chat-handler.js';
3
4
  import { appendMessageReply, createMessage } from '../services/message.js';
4
5
  import { getChannel } from '../services/channel.js';
6
+ import { scheduleChannelTitleGeneration } from '../services/generated-title.js';
5
7
  import * as agentService from '../services/agent.js';
6
8
  import { runMentionedAgent, stopChannelRuns, handleAnswerQuestion, ensureScheduler, makeContext } from './agent-runner.js';
7
9
  import { stripHtml, extractMentionIds } from './html-utils.js';
@@ -10,7 +12,7 @@ export function registerHandler(event, handler) {
10
12
  handlers.set(event, handler);
11
13
  }
12
14
  export function handleConnection(ws, workspaceId) {
13
- addConnection(ws, workspaceId);
15
+ const clientId = addConnection(ws, workspaceId);
14
16
  const ctx = makeContext(workspaceId);
15
17
  ensureScheduler(workspaceId, ctx);
16
18
  ws.send(JSON.stringify({
@@ -52,10 +54,12 @@ for (const evt of terminalEvents) {
52
54
  }
53
55
  // Register channel handlers
54
56
  registerHandler('channel.message', (_ws, workspaceId, data) => {
55
- const { channelId, content, type, mentions, attachments, replyToMessageId } = data;
57
+ const { channelId, content, type, mentions, attachments, replyToMessageId, contextLength } = data;
58
+ const normalizedContextLength = normalizeContextLength(contextLength);
56
59
  if (!channelId || (!content && !attachments?.length))
57
60
  return;
58
- if (!getChannel(workspaceId, channelId))
61
+ const channel = getChannel(workspaceId, channelId);
62
+ if (!channel)
59
63
  return;
60
64
  if (replyToMessageId) {
61
65
  const updated = appendMessageReply(workspaceId, channelId, replyToMessageId, {
@@ -72,8 +76,9 @@ registerHandler('channel.message', (_ws, workspaceId, data) => {
72
76
  void runMentionedAgent(workspaceId, channelId, agentId, stripHtml(content), {
73
77
  messageId: updated.id,
74
78
  appendUserMessage: stripHtml(content),
75
- resumeSessionId: updated.metadata?.runtimeSessionId,
79
+ resumeSessionId: normalizedContextLength > 0 ? updated.metadata?.runtimeSessionId : undefined,
76
80
  excludeHistoryReplyIds: latestReplyId ? [latestReplyId] : undefined,
81
+ contextLength: normalizedContextLength,
77
82
  });
78
83
  }
79
84
  return;
@@ -85,13 +90,27 @@ registerHandler('channel.message', (_ws, workspaceId, data) => {
85
90
  attachments,
86
91
  });
87
92
  broadcastToWorkspace(workspaceId, 'channel.message', message);
93
+ if (!channel.name.trim()) {
94
+ scheduleChannelTitleGeneration({
95
+ workspaceId,
96
+ channelId,
97
+ requirement: stripHtml(content),
98
+ broadcast: (event, payload) => broadcastToWorkspace(workspaceId, event, payload),
99
+ });
100
+ }
88
101
  const agentIds = [...new Set([...(mentions || []), ...extractMentionIds(content)].filter(Boolean))];
89
102
  for (const agentId of agentIds) {
90
103
  void runMentionedAgent(workspaceId, channelId, agentId, stripHtml(content), {
91
104
  excludeHistoryMessageIds: [message.id],
105
+ contextLength: normalizedContextLength,
92
106
  });
93
107
  }
94
108
  });
109
+ function normalizeContextLength(value) {
110
+ if (typeof value !== 'number' || !Number.isFinite(value))
111
+ return 20;
112
+ return Math.min(20, Math.max(0, Math.trunc(value)));
113
+ }
95
114
  registerHandler('channel.stop', (_ws, workspaceId, data) => {
96
115
  const { channelId } = data;
97
116
  if (!channelId)
@@ -115,6 +134,14 @@ registerHandler('agent.stop', (_ws, workspaceId, data) => {
115
134
  to: 'completed',
116
135
  });
117
136
  });
137
+ // Workflow interaction response handler
138
+ registerHandler('workflow:interaction', (ws, _workspaceId, data) => {
139
+ const clientId = getClientId(ws);
140
+ if (clientId)
141
+ handleInteractionResponse(data, clientId);
142
+ });
143
+ // Register chat handlers
144
+ registerChatHandlers();
118
145
  export { broadcastToWorkspace } from './connection-manager.js';
119
146
  export { stopChannelRuns, hasActiveChannelRuns, markInactiveChannelRunsStopped } from './agent-runner.js';
120
147
  //# sourceMappingURL=handler.js.map
@@ -1,5 +1,6 @@
1
1
  export function buildAgentMessageParts(input) {
2
- const lines = normalizeOutputLines(input.output);
2
+ const extractedReasoning = extractInlineReasoning(normalizeOutputLines(input.output));
3
+ const lines = extractedReasoning.lines;
3
4
  const finalTextRange = findFinalTextRange(lines);
4
5
  const finalText = finalTextRange
5
6
  ? collapseRepeatedTextBlock(lines.slice(finalTextRange.start, finalTextRange.end + 1)).join('\n').trim()
@@ -7,7 +8,10 @@ export function buildAgentMessageParts(input) {
7
8
  const usage = input.usage ?? extractUsage(lines);
8
9
  const parts = [];
9
10
  const chainItems = buildChainItems(lines, finalTextRange, finalText, input.workspaceRoot, input.toolDetails, input.persistentContext, input.askUserQuestions);
10
- const reasoningText = normalizeReasoningText(input.reasoning);
11
+ const reasoningText = normalizeReasoningText([
12
+ ...(input.reasoning ?? []),
13
+ ...extractedReasoning.reasoning.map((text) => ({ text })),
14
+ ]);
11
15
  if (reasoningText) {
12
16
  parts.push({
13
17
  id: `reasoning-${input.sessionId}`,
@@ -84,16 +88,43 @@ export function normalizeOutputLines(output) {
84
88
  .map((line) => line.trimEnd())
85
89
  .filter((line) => line.trim());
86
90
  const seenInitLines = new Set();
87
- return lines.filter((line) => {
88
- if (isIgnorableToolProgressLine(line))
89
- return false;
90
- if (!/^Claude Code initialized\b/i.test(line))
91
- return true;
92
- if (seenInitLines.has(line))
93
- return false;
94
- seenInitLines.add(line);
95
- return true;
96
- });
91
+ let inAgentSpacesPromptEcho = false;
92
+ let skipNextUserMessageEchoLine = false;
93
+ const normalizedLines = [];
94
+ for (const line of lines) {
95
+ const cleaned = stripRuntimeNoticePrefix(stripRuntimeLogPrefix(line)).trim();
96
+ if (!cleaned)
97
+ continue;
98
+ if (skipNextUserMessageEchoLine) {
99
+ skipNextUserMessageEchoLine = false;
100
+ continue;
101
+ }
102
+ if (isAgentSpacesPromptEchoStart(cleaned) || /^Agent runtime configuration:\s*$/i.test(cleaned)) {
103
+ inAgentSpacesPromptEcho = true;
104
+ continue;
105
+ }
106
+ if (inAgentSpacesPromptEcho) {
107
+ if (/\bUser message:\s*$/i.test(cleaned)) {
108
+ inAgentSpacesPromptEcho = false;
109
+ skipNextUserMessageEchoLine = true;
110
+ }
111
+ else if (/\bUser message:/i.test(cleaned)) {
112
+ inAgentSpacesPromptEcho = false;
113
+ }
114
+ continue;
115
+ }
116
+ if (isIgnorablePromptEchoLine(cleaned))
117
+ continue;
118
+ if (isIgnorableToolProgressLine(cleaned))
119
+ continue;
120
+ if (/^Claude Code initialized\b/i.test(cleaned)) {
121
+ if (seenInitLines.has(cleaned))
122
+ continue;
123
+ seenInitLines.add(cleaned);
124
+ }
125
+ normalizedLines.push(cleaned);
126
+ }
127
+ return normalizedLines;
97
128
  }
98
129
  export function mergeRuntimeOutput(liveOutput, resultOutput) {
99
130
  if (liveOutput.length === 0)
@@ -192,6 +223,52 @@ function normalizeReasoningText(reasoning) {
192
223
  .map((item) => item.text.trim())
193
224
  .filter(Boolean)).join('\n\n').trim();
194
225
  }
226
+ function extractInlineReasoning(lines) {
227
+ const reasoning = [];
228
+ const outputLines = [];
229
+ let buffer = [];
230
+ let inThinkBlock = false;
231
+ const flushReasoning = () => {
232
+ const text = buffer.join('\n').trim();
233
+ if (text)
234
+ reasoning.push(text);
235
+ buffer = [];
236
+ };
237
+ for (const line of lines) {
238
+ let rest = line;
239
+ let visible = '';
240
+ while (rest) {
241
+ if (inThinkBlock) {
242
+ const closeIndex = rest.search(/<\/think>/i);
243
+ if (closeIndex < 0) {
244
+ buffer.push(rest);
245
+ rest = '';
246
+ continue;
247
+ }
248
+ buffer.push(rest.slice(0, closeIndex));
249
+ flushReasoning();
250
+ rest = rest.slice(closeIndex).replace(/^<\/think>/i, '');
251
+ inThinkBlock = false;
252
+ continue;
253
+ }
254
+ const openIndex = rest.search(/<think>/i);
255
+ if (openIndex < 0) {
256
+ visible += rest;
257
+ rest = '';
258
+ continue;
259
+ }
260
+ visible += rest.slice(0, openIndex);
261
+ rest = rest.slice(openIndex).replace(/^<think>/i, '');
262
+ inThinkBlock = true;
263
+ }
264
+ const cleaned = visible.trimEnd();
265
+ if (cleaned.trim())
266
+ outputLines.push(cleaned);
267
+ }
268
+ if (inThinkBlock)
269
+ flushReasoning();
270
+ return { lines: outputLines, reasoning };
271
+ }
195
272
  function hasTokenUsage(usage) {
196
273
  return Boolean(usage.totalTokens || usage.inputTokens || usage.outputTokens || usage.cachedInputTokens || usage.reasoningTokens);
197
274
  }
@@ -509,6 +586,47 @@ function isIgnorableToolProgressLine(line) {
509
586
  || (isSubagentProgress && /^(Reading|Searching)\s+\S.+$/i.test(trimmed))
510
587
  || /^(Read|Search|Grep|Glob|SemanticSearch|WebSearch)\s+running\s+\(\d+s\)$/i.test(trimmed);
511
588
  }
589
+ function stripRuntimeNoticePrefix(line) {
590
+ let next = line.trim();
591
+ while (next.startsWith('[')) {
592
+ const closeIndex = next.indexOf(']');
593
+ if (closeIndex < 0)
594
+ break;
595
+ const label = next.slice(1, closeIndex);
596
+ if (!isStrippableRuntimeNoticeLabel(label))
597
+ break;
598
+ next = next.slice(closeIndex + 1).trimStart();
599
+ }
600
+ return next;
601
+ }
602
+ function stripRuntimeLogPrefix(line) {
603
+ return line.replace(/^\[[a-z0-9_-]+\]\s+(?:stdout|stderr)\s*\|\s*/i, '');
604
+ }
605
+ function isStrippableRuntimeNoticeLabel(label) {
606
+ return /^Tool loop warning:/i.test(label);
607
+ }
608
+ function isAgentSpacesPromptEchoStart(line) {
609
+ return /^-?\s*Agent Spaces channel tools configured for this channel:/i.test(line);
610
+ }
611
+ function isIgnorablePromptEchoLine(line) {
612
+ return /^-?\s*Code directories \(boundDirs\):/i.test(line)
613
+ || /^-?\s*For Bash commands that create or modify files under the current working\b/i.test(line)
614
+ || /^(directory,|paths\.)$/i.test(line)
615
+ || /^When asked what MCP servers, skills, runtime tools, or Agent Spaces channel tools you have,/i.test(line)
616
+ || /^When asked what MCP servers, skills, runtime tools, or Agent Spaces channel\b/i.test(line)
617
+ || /^tools you have, answer from this configuration only\./i.test(line)
618
+ || /^Important distinction: MCP servers configured for this agent are only the names in /i.test(line)
619
+ || /^Important distinction: MCP servers configured for this agent are only the names\b/i.test(line)
620
+ || /^in "MCP servers configured for this agent"\./i.test(line)
621
+ || /^are$/i.test(line)
622
+ || /^built-in runtime tools and must not be listed as agent-configured MCP servers\./i.test(line)
623
+ || /^Do not infer availability from provider-side function names,/i.test(line)
624
+ || /^Do not infer availability from provider-side function names, hidden runtime\b/i.test(line)
625
+ || /^internals, previous sessions, or filesystem settings\./i.test(line)
626
+ || /^-\s+(Current workspace id|MCP servers configured for this agent|Skills configured for this agent|Runtime tools available through Hermes):/i.test(line)
627
+ || /^skills$/i.test(line)
628
+ || /^User message:/i.test(line);
629
+ }
512
630
  function stripSubagentProgressPrefix(line) {
513
631
  return line.replace(/^\[[^\]]+\]\s+subagent progress\s+\|\s*/i, '');
514
632
  }
@@ -1,7 +1,15 @@
1
1
  import * as ptyService from '../services/pty.js';
2
2
  import { broadcastToWorkspace } from './connection-manager.js';
3
+ const DEBUG_TERMINAL_DUP = '[DEBUG-terminal-dup]';
3
4
  export function sendTerminalSessions(ws, workspaceId) {
4
5
  const existingSessions = ptyService.getSessionsByWorkspace(workspaceId);
6
+ console.log(DEBUG_TERMINAL_DUP, 'server sendTerminalSessions', {
7
+ workspaceId,
8
+ sessions: existingSessions.map(s => ({
9
+ sessionId: s.id,
10
+ bufferLength: s.buffer.join('').length,
11
+ })),
12
+ });
5
13
  ws.send(JSON.stringify({
6
14
  event: 'terminal.sessions',
7
15
  workspaceId,
@@ -20,13 +28,31 @@ export function handleTerminalEvent(ws, workspaceId, event, data) {
20
28
  case 'terminal.create': {
21
29
  const payload = data;
22
30
  const cwd = payload.cwd || process.env.HOME || process.env.USERPROFILE || (process.platform === 'win32' ? process.env.SYSTEMROOT || 'C:\\' : '/tmp');
31
+ console.log(DEBUG_TERMINAL_DUP, 'server terminal.create received', {
32
+ workspaceId,
33
+ sessionId: payload.sessionId,
34
+ shell: payload.shell,
35
+ cwd,
36
+ });
23
37
  try {
24
38
  const sessionId = ptyService.createSession(workspaceId, cwd, (id, output) => {
39
+ console.log(DEBUG_TERMINAL_DUP, 'server terminal.output broadcast', {
40
+ workspaceId,
41
+ sessionId: id,
42
+ outputLength: output.length,
43
+ preview: output.slice(0, 80),
44
+ });
25
45
  broadcastToWorkspace(workspaceId, 'terminal.output', { sessionId: id, data: output });
26
46
  }, (id, exitCode) => {
27
47
  broadcastToWorkspace(workspaceId, 'terminal.closed', { sessionId: id, exitCode });
28
48
  }, payload.shell, undefined, payload.sessionId);
29
49
  const session = ptyService.getSession(sessionId);
50
+ console.log(DEBUG_TERMINAL_DUP, 'server terminal.created broadcast', {
51
+ workspaceId,
52
+ sessionId,
53
+ cwd,
54
+ shell: session?.shell ?? payload.shell,
55
+ });
30
56
  broadcastToWorkspace(workspaceId, 'terminal.created', { sessionId, cwd, shell: session?.shell ?? payload.shell });
31
57
  }
32
58
  catch (err) {