@capybara-hq/kernel 0.1.0-rc.2 → 0.1.0-rc.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 (312) hide show
  1. package/dist/admin/admin.controller.d.ts +9 -4
  2. package/dist/admin/admin.controller.js +13 -4
  3. package/dist/admin/extensions.controller.d.ts +8 -1
  4. package/dist/admin/extensions.controller.js +22 -2
  5. package/dist/agents/agent-lookup.d.ts +3 -0
  6. package/dist/agents/agent-lookup.js +20 -2
  7. package/dist/agents/agent-profile.service.d.ts +29 -0
  8. package/dist/agents/agent-profile.service.js +117 -0
  9. package/dist/agents/agents.controller.d.ts +93 -3
  10. package/dist/agents/agents.controller.js +114 -4
  11. package/dist/agents/agents.module.js +6 -2
  12. package/dist/agents/agents.service.d.ts +13 -5
  13. package/dist/agents/agents.service.js +49 -13
  14. package/dist/agents/definition.d.ts +35 -8
  15. package/dist/agents/definition.js +203 -17
  16. package/dist/agents/instruction-files.d.ts +60 -0
  17. package/dist/agents/instruction-files.js +111 -0
  18. package/dist/agents/models.controller.d.ts +9 -3
  19. package/dist/agents/models.controller.js +19 -4
  20. package/dist/agents/profile.d.ts +96 -0
  21. package/dist/agents/profile.js +51 -0
  22. package/dist/agents/readiness.controller.d.ts +26 -0
  23. package/dist/agents/readiness.controller.js +56 -0
  24. package/dist/agents/templates.js +20 -5
  25. package/dist/background/background.controller.d.ts +38 -0
  26. package/dist/background/background.controller.js +87 -0
  27. package/dist/background/background.module.d.ts +10 -0
  28. package/dist/background/background.module.js +32 -0
  29. package/dist/background/finish.d.ts +43 -0
  30. package/dist/background/finish.js +94 -0
  31. package/dist/background/launch-lock.d.ts +14 -0
  32. package/dist/background/launch-lock.js +39 -0
  33. package/dist/background/launch.d.ts +36 -0
  34. package/dist/background/launch.js +70 -0
  35. package/dist/background/poll.job.d.ts +53 -0
  36. package/dist/background/poll.job.js +182 -0
  37. package/dist/background/render.d.ts +23 -0
  38. package/dist/background/render.js +48 -0
  39. package/dist/background/session.d.ts +37 -0
  40. package/dist/background/session.js +66 -0
  41. package/dist/background/status.d.ts +35 -0
  42. package/dist/background/status.js +57 -0
  43. package/dist/background/stop.d.ts +62 -0
  44. package/dist/background/stop.js +225 -0
  45. package/dist/background/store.d.ts +150 -0
  46. package/dist/background/store.js +351 -0
  47. package/dist/background/store.module.d.ts +6 -0
  48. package/dist/background/store.module.js +22 -0
  49. package/dist/background/tasks.service.d.ts +67 -0
  50. package/dist/background/tasks.service.js +186 -0
  51. package/dist/background/wake-rules.d.ts +57 -0
  52. package/dist/background/wake-rules.js +83 -0
  53. package/dist/background/wake.d.ts +28 -0
  54. package/dist/background/wake.js +57 -0
  55. package/dist/catalog/catalog-content.js +4 -1
  56. package/dist/catalog/claude/agents.js +15 -10
  57. package/dist/catalog/marketplaces.service.d.ts +1 -1
  58. package/dist/catalog/plugin-import.js +1 -1
  59. package/dist/catalog/plugin-upgrade.js +1 -1
  60. package/dist/channels/cards.d.ts +8 -2
  61. package/dist/channels/cards.js +17 -9
  62. package/dist/channels/connections.service.d.ts +16 -1
  63. package/dist/channels/connections.service.js +38 -4
  64. package/dist/channels/threads.d.ts +5 -0
  65. package/dist/channels/threads.js +8 -0
  66. package/dist/config/schema.d.ts +18 -0
  67. package/dist/config/schema.js +104 -2
  68. package/dist/conversations/access.js +2 -0
  69. package/dist/conversations/artifacts.d.ts +1 -1
  70. package/dist/conversations/artifacts.js +1 -1
  71. package/dist/conversations/attachments.service.d.ts +30 -0
  72. package/dist/conversations/attachments.service.js +130 -5
  73. package/dist/conversations/conversations.controller.d.ts +36 -5
  74. package/dist/conversations/conversations.controller.js +62 -12
  75. package/dist/conversations/conversations.module.js +3 -0
  76. package/dist/conversations/conversations.service.d.ts +44 -2
  77. package/dist/conversations/conversations.service.js +140 -12
  78. package/dist/conversations/event-log.d.ts +12 -1
  79. package/dist/conversations/event-log.js +29 -1
  80. package/dist/conversations/events.d.ts +81 -3
  81. package/dist/conversations/events.js +83 -16
  82. package/dist/conversations/queue.d.ts +3 -1
  83. package/dist/conversations/queue.js +13 -2
  84. package/dist/conversations/queue.service.js +3 -1
  85. package/dist/conversations/titles.d.ts +7 -0
  86. package/dist/conversations/titles.js +15 -0
  87. package/dist/db/kernel-schema.d.ts +60 -4
  88. package/dist/db/pool.d.ts +5 -0
  89. package/dist/db/pool.js +3 -0
  90. package/dist/errors.d.ts +8 -0
  91. package/dist/errors.js +8 -0
  92. package/dist/evals/recorded-tools.d.ts +27 -1
  93. package/dist/evals/recorded-tools.js +85 -10
  94. package/dist/evals/run-replay.d.ts +10 -2
  95. package/dist/evals/run-replay.js +49 -12
  96. package/dist/evals/step-replay.js +12 -6
  97. package/dist/evals/trajectory.d.ts +2 -2
  98. package/dist/evals/trajectory.js +1 -1
  99. package/dist/extensions/admin-ops.js +2 -0
  100. package/dist/extensions/admin-view.d.ts +3 -1
  101. package/dist/extensions/admin-view.js +10 -2
  102. package/dist/extensions/blobs.js +1 -0
  103. package/dist/extensions/config-issues.d.ts +13 -1
  104. package/dist/extensions/config-issues.js +22 -5
  105. package/dist/extensions/config-json-schema.d.ts +43 -7
  106. package/dist/extensions/config-json-schema.js +124 -58
  107. package/dist/extensions/deployment-config-store.d.ts +6 -0
  108. package/dist/extensions/deployment-config.d.ts +50 -3
  109. package/dist/extensions/deployment-config.js +125 -28
  110. package/dist/extensions/display-name.d.ts +22 -0
  111. package/dist/extensions/display-name.js +77 -0
  112. package/dist/extensions/extensions.module.js +6 -0
  113. package/dist/extensions/host.d.ts +26 -1
  114. package/dist/extensions/host.js +82 -9
  115. package/dist/extensions/org-config.controller.d.ts +11 -3
  116. package/dist/extensions/org-config.controller.js +14 -6
  117. package/dist/extensions/org-config.d.ts +6 -0
  118. package/dist/extensions/org-config.js +12 -13
  119. package/dist/extensions/package.d.ts +14 -1
  120. package/dist/extensions/package.js +51 -2
  121. package/dist/extensions/permission-view.d.ts +3 -0
  122. package/dist/extensions/point-defaults.controller.d.ts +34 -0
  123. package/dist/extensions/point-defaults.controller.js +71 -0
  124. package/dist/extensions/point-defaults.d.ts +64 -0
  125. package/dist/extensions/point-defaults.js +206 -0
  126. package/dist/extensions/registry.d.ts +1 -1
  127. package/dist/extensions/registry.js +2 -0
  128. package/dist/http/api.module.js +8 -0
  129. package/dist/http/nest-logger.d.ts +6 -5
  130. package/dist/http/nest-logger.js +24 -10
  131. package/dist/identity/auth.controller.js +9 -5
  132. package/dist/identity/cookies.d.ts +20 -5
  133. package/dist/identity/cookies.js +44 -6
  134. package/dist/identity/me.controller.d.ts +5 -1
  135. package/dist/identity/me.controller.js +12 -3
  136. package/dist/identity/sessions.d.ts +12 -0
  137. package/dist/identity/sessions.js +45 -0
  138. package/dist/identity/settings.js +1 -1
  139. package/dist/index.d.ts +1 -1
  140. package/dist/infra/config/kernel-config.service.js +6 -0
  141. package/dist/infra/database/database.module.js +1 -0
  142. package/dist/infra/events/kernel-events.d.ts +8 -0
  143. package/dist/infra/lifecycle/process-guards.js +4 -0
  144. package/dist/infra/logging/logging.module.d.ts +4 -2
  145. package/dist/infra/logging/logging.module.js +24 -6
  146. package/dist/infra/queue/redis-connection.d.ts +6 -0
  147. package/dist/infra/queue/redis-connection.js +7 -0
  148. package/dist/infra/redis/redis.module.js +6 -2
  149. package/dist/infra/tokens.d.ts +6 -1
  150. package/dist/infra/tokens.js +6 -1
  151. package/dist/lifecycle/kernel-lifecycle.js +5 -0
  152. package/dist/log.d.ts +13 -1
  153. package/dist/log.js +93 -17
  154. package/dist/models/purposes.d.ts +23 -0
  155. package/dist/models/purposes.js +31 -10
  156. package/dist/orgs/offboarding.d.ts +3 -1
  157. package/dist/orgs/offboarding.js +26 -16
  158. package/dist/orgs/settings.service.d.ts +7 -2
  159. package/dist/orgs/settings.service.js +15 -4
  160. package/dist/roles/worker.module.js +6 -0
  161. package/dist/runtime/context/build.d.ts +15 -13
  162. package/dist/runtime/context/build.js +45 -27
  163. package/dist/runtime/context/claude-tools.d.ts +3 -1
  164. package/dist/runtime/context/claude-tools.js +12 -12
  165. package/dist/runtime/context/compaction.js +4 -0
  166. package/dist/runtime/context/legacy-text.d.ts +22 -0
  167. package/dist/runtime/context/legacy-text.js +37 -0
  168. package/dist/runtime/context/skills.d.ts +29 -11
  169. package/dist/runtime/context/skills.js +37 -30
  170. package/dist/runtime/langgraph-loop.js +3 -2
  171. package/dist/runtime/loop.d.ts +5 -4
  172. package/dist/runtime/maintenance.d.ts +4 -2
  173. package/dist/runtime/maintenance.js +17 -5
  174. package/dist/runtime/model-call.d.ts +17 -1
  175. package/dist/runtime/model-call.js +4 -3
  176. package/dist/runtime/providers.d.ts +6 -0
  177. package/dist/runtime/providers.js +8 -0
  178. package/dist/runtime/run-finish.d.ts +1 -1
  179. package/dist/runtime/run-queue.d.ts +28 -5
  180. package/dist/runtime/run-queue.js +131 -35
  181. package/dist/runtime/run-worker.d.ts +2 -2
  182. package/dist/runtime/run-worker.js +20 -7
  183. package/dist/runtime/runtime.module.js +8 -3
  184. package/dist/runtime/step-log.d.ts +6 -0
  185. package/dist/runtime/step-log.js +16 -2
  186. package/dist/runtime/subagents/definition.d.ts +1 -6
  187. package/dist/runtime/subagents/definition.js +14 -13
  188. package/dist/runtime/subagents/dispatch.d.ts +2 -2
  189. package/dist/runtime/subagents/dispatch.js +2 -2
  190. package/dist/runtime/subagents/org-agents.js +2 -1
  191. package/dist/runtime/subagents/roster.d.ts +1 -1
  192. package/dist/runtime/subagents/roster.js +1 -1
  193. package/dist/runtime/subagents/skill-fork.d.ts +2 -2
  194. package/dist/runtime/subagents/skill-fork.js +2 -2
  195. package/dist/runtime/subagents/subagents.service.d.ts +3 -3
  196. package/dist/runtime/subagents/subagents.service.js +3 -3
  197. package/dist/runtime/usage-report.d.ts +2 -1
  198. package/dist/runtime/usage-report.js +2 -1
  199. package/dist/runtime/waits.d.ts +13 -7
  200. package/dist/runtime/waits.js +42 -16
  201. package/dist/sandbox/sandbox.module.js +6 -1
  202. package/dist/sandbox/sandbox.service.d.ts +61 -3
  203. package/dist/sandbox/sandbox.service.js +141 -7
  204. package/dist/skills/catalog.d.ts +4 -4
  205. package/dist/skills/catalog.js +4 -4
  206. package/dist/skills/changes.service.d.ts +2 -2
  207. package/dist/skills/changes.service.js +5 -4
  208. package/dist/skills/invocation-keys.d.ts +1 -1
  209. package/dist/skills/invocation-keys.js +1 -1
  210. package/dist/skills/invoke.d.ts +1 -1
  211. package/dist/skills/invoke.js +5 -4
  212. package/dist/tools/approvals.service.d.ts +6 -0
  213. package/dist/tools/approvals.service.js +21 -1
  214. package/dist/tools/builtin-names.d.ts +91 -0
  215. package/dist/tools/builtin-names.js +143 -0
  216. package/dist/tools/builtins/agent.d.ts +7 -7
  217. package/dist/tools/builtins/agent.js +7 -11
  218. package/dist/tools/builtins/ask-user.d.ts +1 -1
  219. package/dist/tools/builtins/ask-user.js +2 -2
  220. package/dist/tools/builtins/builtin-tools.d.ts +17 -3
  221. package/dist/tools/builtins/builtin-tools.js +36 -4
  222. package/dist/tools/builtins/read-tool-output.d.ts +1 -1
  223. package/dist/tools/builtins/read-tool-output.js +2 -2
  224. package/dist/tools/builtins/sandbox/bash.d.ts +4 -4
  225. package/dist/tools/builtins/sandbox/bash.js +259 -29
  226. package/dist/tools/builtins/sandbox/common.d.ts +30 -7
  227. package/dist/tools/builtins/sandbox/common.js +9 -5
  228. package/dist/tools/builtins/sandbox/deliver.d.ts +1 -1
  229. package/dist/tools/builtins/sandbox/deliver.js +12 -12
  230. package/dist/tools/builtins/sandbox/edit.d.ts +1 -1
  231. package/dist/tools/builtins/sandbox/edit.js +41 -30
  232. package/dist/tools/builtins/sandbox/file-state.d.ts +34 -0
  233. package/dist/tools/builtins/sandbox/file-state.js +34 -0
  234. package/dist/tools/builtins/sandbox/glob-match.d.ts +1 -1
  235. package/dist/tools/builtins/sandbox/glob-match.js +1 -1
  236. package/dist/tools/builtins/sandbox/glob.d.ts +1 -1
  237. package/dist/tools/builtins/sandbox/glob.js +4 -4
  238. package/dist/tools/builtins/sandbox/grep.d.ts +7 -4
  239. package/dist/tools/builtins/sandbox/grep.js +147 -30
  240. package/dist/tools/builtins/sandbox/index.d.ts +3 -1
  241. package/dist/tools/builtins/sandbox/index.js +7 -1
  242. package/dist/tools/builtins/sandbox/read.d.ts +2 -2
  243. package/dist/tools/builtins/sandbox/read.js +21 -14
  244. package/dist/tools/builtins/sandbox/task-output.d.ts +63 -0
  245. package/dist/tools/builtins/sandbox/task-output.js +304 -0
  246. package/dist/tools/builtins/sandbox/task-stop.d.ts +10 -0
  247. package/dist/tools/builtins/sandbox/task-stop.js +112 -0
  248. package/dist/tools/builtins/sandbox/write.d.ts +1 -1
  249. package/dist/tools/builtins/sandbox/write.js +37 -33
  250. package/dist/tools/builtins/skill-load.d.ts +3 -3
  251. package/dist/tools/builtins/skill-load.js +32 -16
  252. package/dist/tools/builtins/skill-write.d.ts +4 -4
  253. package/dist/tools/builtins/skill-write.js +10 -10
  254. package/dist/tools/builtins/tool-search.d.ts +13 -9
  255. package/dist/tools/builtins/tool-search.js +25 -14
  256. package/dist/tools/builtins/web/errors.d.ts +8 -0
  257. package/dist/tools/builtins/web/errors.js +53 -0
  258. package/dist/tools/builtins/web/extract.d.ts +62 -0
  259. package/dist/tools/builtins/web/extract.js +267 -0
  260. package/dist/tools/builtins/web/fetch.d.ts +55 -0
  261. package/dist/tools/builtins/web/fetch.js +174 -0
  262. package/dist/tools/builtins/web/index.d.ts +13 -0
  263. package/dist/tools/builtins/web/index.js +12 -0
  264. package/dist/tools/builtins/web/page-cache.d.ts +25 -0
  265. package/dist/tools/builtins/web/page-cache.js +77 -0
  266. package/dist/tools/builtins/web/search.d.ts +25 -0
  267. package/dist/tools/builtins/web/search.js +209 -0
  268. package/dist/tools/builtins/web/url.d.ts +17 -0
  269. package/dist/tools/builtins/web/url.js +43 -0
  270. package/dist/tools/connectors.service.js +4 -4
  271. package/dist/tools/display-names.d.ts +9 -0
  272. package/dist/tools/display-names.js +24 -0
  273. package/dist/tools/drift.js +5 -5
  274. package/dist/tools/elicitation.js +1 -1
  275. package/dist/tools/info.d.ts +20 -4
  276. package/dist/tools/info.js +55 -32
  277. package/dist/tools/legacy-data.d.ts +34 -0
  278. package/dist/tools/legacy-data.js +76 -0
  279. package/dist/tools/legacy-keys.d.ts +51 -0
  280. package/dist/tools/legacy-keys.js +115 -0
  281. package/dist/tools/naming.d.ts +1 -5
  282. package/dist/tools/naming.js +1 -7
  283. package/dist/tools/oauth/flow-paths.d.ts +1 -1
  284. package/dist/tools/oauth/flow-paths.js +1 -1
  285. package/dist/tools/outputs.js +1 -1
  286. package/dist/tools/pipeline.d.ts +13 -7
  287. package/dist/tools/pipeline.js +112 -39
  288. package/dist/tools/policy.d.ts +1 -14
  289. package/dist/tools/policy.js +13 -19
  290. package/dist/tools/questions.controller.d.ts +1 -1
  291. package/dist/tools/questions.controller.js +1 -1
  292. package/dist/tools/questions.service.d.ts +1 -1
  293. package/dist/tools/registry.d.ts +38 -24
  294. package/dist/tools/registry.js +54 -47
  295. package/dist/tools/resources.d.ts +1 -1
  296. package/dist/tools/resources.js +1 -1
  297. package/dist/tools/tools.module.js +13 -1
  298. package/dist/tools/validate.js +1 -1
  299. package/package.json +3 -3
  300. package/src/migrations/0063_tool_keys_claude_code.sql +220 -0
  301. package/src/migrations/0064_account_last_org.sql +7 -0
  302. package/src/migrations/0065_conversation_archive.sql +8 -0
  303. package/src/migrations/0066_extension_display_name.sql +4 -0
  304. package/src/migrations/0067_agent_profiles.sql +20 -0
  305. package/src/migrations/0068_agent_avatar_uploads.sql +7 -0
  306. package/src/migrations/0069_attachments_agent_idx.sql +3 -0
  307. package/src/migrations/0070_background_tasks.sql +37 -0
  308. package/src/migrations/0071_background_tasks_reserve.sql +6 -0
  309. package/src/migrations/0072_background_tasks_stopping.sql +5 -0
  310. package/src/migrations/0073_org_extension_point_defaults.sql +11 -0
  311. package/dist/tools/builtins/sandbox/names.d.ts +0 -7
  312. package/dist/tools/builtins/sandbox/names.js +0 -20
@@ -179,6 +179,14 @@ export const KernelConfigSchema = z.object({
179
179
  .positive()
180
180
  .default(5000)
181
181
  .meta(meta({ description: "PostgreSQL connect timeout in milliseconds" })),
182
+ idleTimeoutMs: z
183
+ .number()
184
+ .int()
185
+ .positive()
186
+ .default(60_000)
187
+ .meta(meta({
188
+ description: "How long an idle PostgreSQL connection stays in the pool, in milliseconds",
189
+ })),
182
190
  })
183
191
  .prefault({}),
184
192
  redis: z
@@ -568,6 +576,12 @@ export const KernelConfigSchema = z.object({
568
576
  .positive()
569
577
  .default(50)
570
578
  .meta(meta({ description: "Maximum model steps per agent run before the final wrap-up" })),
579
+ wakeOnBackgroundTask: z
580
+ .boolean()
581
+ .default(true)
582
+ .meta(meta({
583
+ description: "Whether the finish of a background Bash task starts a run on an idle conversation (the person who started the task's run is the trigger); an organization can override it in its settings. When false the event is only logged and shown, and the next message picks it up",
584
+ })),
571
585
  maxRunSeconds: z
572
586
  .number()
573
587
  .int()
@@ -656,6 +670,7 @@ export const KernelConfigSchema = z.object({
656
670
  })
657
671
  .default({
658
672
  maxSteps: 50,
673
+ wakeOnBackgroundTask: true,
659
674
  maxRunSeconds: DEFAULT_MAX_RUN_SECONDS,
660
675
  streamIdleMs: 60000,
661
676
  maxOutputTokens: 16000,
@@ -751,7 +766,7 @@ export const KernelConfigSchema = z.object({
751
766
  .int()
752
767
  .positive()
753
768
  .default(20000)
754
- .meta(meta({ description: "Maximum characters returned by one read_tool_output call" })),
769
+ .meta(meta({ description: "Maximum characters returned by one ReadToolOutput call" })),
755
770
  oauthAllowInsecureLoopback: z
756
771
  .boolean()
757
772
  .default(false)
@@ -946,6 +961,64 @@ export const KernelConfigSchema = z.object({
946
961
  })),
947
962
  })
948
963
  .prefault({}),
964
+ web: z
965
+ .object({
966
+ search: z
967
+ .object({
968
+ maxResults: z
969
+ .number()
970
+ .int()
971
+ .min(1)
972
+ .max(20)
973
+ .default(10)
974
+ .meta(meta({
975
+ hot: true,
976
+ description: "Maximum number of results one WebSearch call returns to the model, however many the search provider returns",
977
+ })),
978
+ })
979
+ .prefault({}),
980
+ fetch: z
981
+ .object({
982
+ maxPageChars: z
983
+ .number()
984
+ .int()
985
+ .positive()
986
+ .default(400_000)
987
+ .meta(meta({
988
+ hot: true,
989
+ description: "Maximum characters of a fetched page kept for answering a WebFetch prompt; longer pages are truncated",
990
+ })),
991
+ maxAnswerTokens: z
992
+ .number()
993
+ .int()
994
+ .positive()
995
+ .default(4000)
996
+ .meta(meta({
997
+ hot: true,
998
+ description: "Maximum output tokens of the model call that answers a WebFetch prompt from the page",
999
+ })),
1000
+ cacheSeconds: z
1001
+ .number()
1002
+ .int()
1003
+ .min(0)
1004
+ .default(900)
1005
+ .meta(meta({
1006
+ hot: true,
1007
+ description: "Seconds a fetched page is cached per organization and URL; 0 turns the cache off",
1008
+ })),
1009
+ timeoutMs: z
1010
+ .number()
1011
+ .int()
1012
+ .positive()
1013
+ .default(180_000)
1014
+ .meta(meta({
1015
+ hot: true,
1016
+ description: "Time limit of one WebFetch call in milliseconds, the provider's fetch and the answering model call together; replaces tools.timeoutMs for WebFetch",
1017
+ })),
1018
+ })
1019
+ .prefault({}),
1020
+ })
1021
+ .prefault({}),
949
1022
  sandbox: z
950
1023
  .object({
951
1024
  image: z
@@ -978,8 +1051,37 @@ export const KernelConfigSchema = z.object({
978
1051
  .positive()
979
1052
  .default(104_857_600)
980
1053
  .meta(meta({
981
- description: "Largest file in bytes an agent may deliver from its sandbox to the user as an artifact (sandbox_deliver)",
1054
+ description: "Largest file in bytes an agent may deliver from its sandbox to the user as an artifact (Deliver)",
982
1055
  })),
1056
+ background: z
1057
+ .object({
1058
+ maxTasks: z
1059
+ .number()
1060
+ .int()
1061
+ .min(1)
1062
+ .max(100)
1063
+ .default(4)
1064
+ .meta(meta({
1065
+ description: "Most background Bash tasks (run_in_background) that may run at once in one conversation's sandbox, sub-agents included; a launch beyond it is refused",
1066
+ })),
1067
+ maxSeconds: z
1068
+ .number()
1069
+ .int()
1070
+ .positive()
1071
+ .default(7200)
1072
+ .meta(meta({
1073
+ description: "Longest a background Bash task may run, in seconds; the task is killed at its deadline and ends as timed_out. Clamped to sandbox.limits.maxCommandSeconds; not limited by runtime.maxRunSeconds",
1074
+ })),
1075
+ pollSeconds: z
1076
+ .number()
1077
+ .int()
1078
+ .min(1)
1079
+ .default(10)
1080
+ .meta(meta({
1081
+ description: "How often the worker checks the running background Bash tasks of every sandbox for a finish, in seconds; read when the worker starts",
1082
+ })),
1083
+ })
1084
+ .prefault({}),
983
1085
  limits: z
984
1086
  .object({
985
1087
  cpu: z
@@ -27,6 +27,7 @@ export const parentReachable = (viewerAccountId) => (eb) => eb.or([
27
27
  .whereRef("p.org_id", "=", "conversations.org_id")
28
28
  .where("p.account_id", "=", viewerAccountId)
29
29
  .where("p.kind", "=", "chat")
30
+ .where("p.deleted_at", "is", null)
30
31
  .where("agents.deleted_at", "is", null)
31
32
  .where(visibleTo(viewerAccountId))),
32
33
  ]);
@@ -53,6 +54,7 @@ let ConversationAccess = class ConversationAccess {
53
54
  .where("conversations.id", "=", conversationId)
54
55
  .where("conversations.org_id", "=", orgId)
55
56
  .where("conversations.account_id", "=", viewerAccountId)
57
+ .where("conversations.deleted_at", "is", null)
56
58
  .where("conversations.kind", "in", ["chat", "subagent"])
57
59
  .where(parentReachable(viewerAccountId))
58
60
  .where((eb) => eb.and([
@@ -20,7 +20,7 @@ export interface ArtifactPreview {
20
20
  truncated: boolean;
21
21
  }
22
22
  /**
23
- * 产物(M5 T8 / T11):agent 经 `sandbox_deliver` 交付的文件。先按会话流的规则判定会话可见
23
+ * 产物(M5 T8 / T11):agent 经 `Deliver` 交付的文件。先按会话流的规则判定会话可见
24
24
  * (不可见 → `conversation.not_found`),再只在这个会话的日志里找 `artifact_created`
25
25
  * (没有 → `conversation.artifact_not_found`)。
26
26
  *
@@ -62,7 +62,7 @@ async function readPrefix(body, max) {
62
62
  return out.subarray(0, n);
63
63
  }
64
64
  /**
65
- * 产物(M5 T8 / T11):agent 经 `sandbox_deliver` 交付的文件。先按会话流的规则判定会话可见
65
+ * 产物(M5 T8 / T11):agent 经 `Deliver` 交付的文件。先按会话流的规则判定会话可见
66
66
  * (不可见 → `conversation.not_found`),再只在这个会话的日志里找 `artifact_created`
67
67
  * (没有 → `conversation.artifact_not_found`)。
68
68
  *
@@ -28,6 +28,16 @@ export declare const MAX_PENDING_SKILL_PACKAGES = 5;
28
28
  * `POST /skills` 开始处理时再顺延这么久,处理期间不会被清理。
29
29
  */
30
30
  export declare const SKILL_PACKAGE_TTL_HOURS = 1;
31
+ /** The image types an agent avatar upload may have (cropped square in the browser). */
32
+ export declare const AGENT_AVATAR_CONTENT_TYPES: readonly ["image/png", "image/jpeg", "image/webp"];
33
+ /** The size limit of an agent avatar upload (bytes). */
34
+ export declare const AGENT_AVATAR_MAX_BYTES: number;
35
+ /** Unfinished avatar uploads one account may have in an org (counted apart from other uploads). */
36
+ export declare const MAX_PENDING_AGENT_AVATARS = 10;
37
+ /** An avatar upload not saved into a profile expires (and is cleaned up) after this many hours. */
38
+ export declare const AGENT_AVATAR_TTL_HOURS = 24;
39
+ /** Download redirect lifetime of an avatar (seconds); also its `Cache-Control` max-age. */
40
+ export declare const AGENT_AVATAR_DOWNLOAD_TTL_SECONDS = 300;
31
41
  /**
32
42
  * 技能包解出的文件在 `kernel/<orgId>/` 下的前缀:按上传 id,同一上传重试写到同一批键(幂等),
33
43
  * 并发处理同一上传也不会互相覆盖出不同内容。版本行记下这个前缀(`skill_versions.object_prefix`)。
@@ -169,6 +179,26 @@ export declare class AttachmentsService {
169
179
  * 不是该账号的 ready 技能包(如已被并发的请求用掉)→ `attachment.not_found`。
170
180
  */
171
181
  consumeSkillPackage(orgId: string, accountId: string, id: string): Promise<void>;
182
+ /**
183
+ * Makes an agent avatar upload ready to be saved into a profile (outside any transaction: it may
184
+ * read the object store): only the uploader, only the `agent-avatar` purpose, an image type, not
185
+ * expired and not yet used by another agent, else `attachment.not_found`. An upload still
186
+ * `pending` is finalized first (size, type and the image signature are checked). The expiry is
187
+ * extended so the cleanup job cannot delete it before {@link consumeAgentAvatar} runs.
188
+ */
189
+ prepareAgentAvatar(orgId: string, accountId: string, id: string, agentId: string): Promise<void>;
190
+ /**
191
+ * In the caller's transaction, binds a ready avatar upload to `agentId` (row lock; the expiry is
192
+ * cleared, so the cleanup job keeps it while the profile uses it). An upload another agent
193
+ * already uses, or one that is not the account's ready avatar → `attachment.not_found`; saving
194
+ * the same upload to the same agent again is fine.
195
+ */
196
+ consumeAgentAvatar(orgId: string, accountId: string, id: string, agentId: string): Promise<void>;
197
+ /**
198
+ * A short-lived presigned GET (inline, with the checked image type) of the avatar upload bound
199
+ * to `agentId`; `null` when there is none or its object is gone or no longer the finalized one.
200
+ */
201
+ agentAvatarUrl(orgId: string, agentId: string, id: string): Promise<string | null>;
172
202
  /**
173
203
  * 删除过期(`expires_at < now()`)且从未绑定到会话的附件:先把行认领为 `deleting`(`FOR UPDATE SKIP LOCKED`,
174
204
  * 多副本并发时互不重复),再删对象、删行。删对象失败的行保持 `deleting`,下次运行重试。
@@ -40,6 +40,16 @@ export const MAX_PENDING_SKILL_PACKAGES = 5;
40
40
  * `POST /skills` 开始处理时再顺延这么久,处理期间不会被清理。
41
41
  */
42
42
  export const SKILL_PACKAGE_TTL_HOURS = 1;
43
+ /** The image types an agent avatar upload may have (cropped square in the browser). */
44
+ export const AGENT_AVATAR_CONTENT_TYPES = ["image/png", "image/jpeg", "image/webp"];
45
+ /** The size limit of an agent avatar upload (bytes). */
46
+ export const AGENT_AVATAR_MAX_BYTES = 2 * 1024 * 1024;
47
+ /** Unfinished avatar uploads one account may have in an org (counted apart from other uploads). */
48
+ export const MAX_PENDING_AGENT_AVATARS = 10;
49
+ /** An avatar upload not saved into a profile expires (and is cleaned up) after this many hours. */
50
+ export const AGENT_AVATAR_TTL_HOURS = 24;
51
+ /** Download redirect lifetime of an avatar (seconds); also its `Cache-Control` max-age. */
52
+ export const AGENT_AVATAR_DOWNLOAD_TTL_SECONDS = 300;
43
53
  /**
44
54
  * 技能包解出的文件在 `kernel/<orgId>/` 下的前缀:按上传 id,同一上传重试写到同一批键(幂等),
45
55
  * 并发处理同一上传也不会互相覆盖出不同内容。版本行记下这个前缀(`skill_versions.object_prefix`)。
@@ -56,7 +66,11 @@ const notFound = () => new ApiError("attachment.not_found", "Attachment not foun
56
66
  export const normalizeContentType = (ct) => (ct.split(";")[0] ?? "").trim().toLowerCase();
57
67
  const isImage = (ct) => IMAGE_MEDIA_TYPES.includes(ct);
58
68
  /** 对象键:只用附件 id,用户的文件名不进键。技能包另放 `skill-packages/<id>`。 */
59
- const objectKey = (id, purpose = "chat") => purpose === "chat" ? `attachments/${id}` : `skill-packages/${id}`;
69
+ const objectKey = (id, purpose = "chat") => purpose === "chat"
70
+ ? `attachments/${id}`
71
+ : purpose === "agent-avatar"
72
+ ? `agent-avatars/${id}`
73
+ : `skill-packages/${id}`;
60
74
  const startsWith = (b, sig, at = 0) => sig.every((x, i) => b[at + i] === x);
61
75
  const ascii = (s) => [...s].map((c) => c.charCodeAt(0));
62
76
  /** 文件开头是否与声明的类型相符(图片与 PDF 看签名,文本不能含 NUL)。 */
@@ -139,12 +153,19 @@ let AttachmentsService = class AttachmentsService {
139
153
  const cfg = this.config.get().attachments;
140
154
  const contentType = normalizeContentType(input.contentType);
141
155
  const skill = purpose === "skill-package";
156
+ const avatar = purpose === "agent-avatar";
142
157
  if (skill
143
158
  ? contentType !== SKILL_PACKAGE_CONTENT_TYPE
144
- : !cfg.allowedTypes.includes(contentType)) {
159
+ : avatar
160
+ ? !AGENT_AVATAR_CONTENT_TYPES.includes(contentType)
161
+ : !cfg.allowedTypes.includes(contentType)) {
145
162
  throw new ApiError("attachment.type_not_allowed", `Attachment type ${JSON.stringify(contentType)} is not allowed`);
146
163
  }
147
- const limit = skill ? SKILL_PACKAGE_UPLOAD_MAX_BYTES : this.limitFor(contentType);
164
+ const limit = skill
165
+ ? SKILL_PACKAGE_UPLOAD_MAX_BYTES
166
+ : avatar
167
+ ? AGENT_AVATAR_MAX_BYTES
168
+ : this.limitFor(contentType);
148
169
  if (input.size > limit) {
149
170
  throw new ApiError("attachment.too_large", `Attachment is ${input.size} bytes, over the limit of ${limit} bytes`);
150
171
  }
@@ -156,13 +177,21 @@ let AttachmentsService = class AttachmentsService {
156
177
  .where("status", "=", "pending")
157
178
  .where("purpose", "=", purpose)
158
179
  .executeTakeFirst();
159
- const maxPending = skill ? MAX_PENDING_SKILL_PACKAGES : MAX_PENDING_ATTACHMENTS;
180
+ const maxPending = skill
181
+ ? MAX_PENDING_SKILL_PACKAGES
182
+ : avatar
183
+ ? MAX_PENDING_AGENT_AVATARS
184
+ : MAX_PENDING_ATTACHMENTS;
160
185
  if (Number(pending?.n ?? 0) >= maxPending) {
161
186
  throw new ApiError("attachment.too_many_pending", `Too many unfinished uploads (at most ${maxPending}); finish or wait for them first`);
162
187
  }
163
188
  const id = randomUUID();
164
189
  const key = objectKey(id, purpose);
165
- const ttlHours = skill ? SKILL_PACKAGE_TTL_HOURS : cfg.unboundTtlHours;
190
+ const ttlHours = skill
191
+ ? SKILL_PACKAGE_TTL_HOURS
192
+ : avatar
193
+ ? AGENT_AVATAR_TTL_HOURS
194
+ : cfg.unboundTtlHours;
166
195
  const upload = await this.storage.kernel(orgId).presignPut(key, {
167
196
  contentType,
168
197
  maxSize: input.size,
@@ -541,6 +570,99 @@ let AttachmentsService = class AttachmentsService {
541
570
  .where("id", "=", id)
542
571
  .execute();
543
572
  }
573
+ /**
574
+ * Makes an agent avatar upload ready to be saved into a profile (outside any transaction: it may
575
+ * read the object store): only the uploader, only the `agent-avatar` purpose, an image type, not
576
+ * expired and not yet used by another agent, else `attachment.not_found`. An upload still
577
+ * `pending` is finalized first (size, type and the image signature are checked). The expiry is
578
+ * extended so the cleanup job cannot delete it before {@link consumeAgentAvatar} runs.
579
+ */
580
+ async prepareAgentAvatar(orgId, accountId, id, agentId) {
581
+ this.storage.assertAvailable();
582
+ const row = await this.db
583
+ .selectFrom("attachments")
584
+ .select([
585
+ "status",
586
+ "purpose",
587
+ "content_type",
588
+ "agent_id",
589
+ sql `expires_at is not null and expires_at <= now()`.as("expired"),
590
+ ])
591
+ .where("id", "=", id)
592
+ .where("org_id", "=", orgId)
593
+ .where("account_id", "=", accountId)
594
+ .executeTakeFirst();
595
+ if (row?.purpose !== "agent-avatar" ||
596
+ row.status === "deleting" ||
597
+ row.expired ||
598
+ (row.agent_id !== null && row.agent_id !== agentId) ||
599
+ !AGENT_AVATAR_CONTENT_TYPES.includes(row.content_type)) {
600
+ throw notFound();
601
+ }
602
+ if (row.status === "pending")
603
+ await this.finalize(orgId, accountId, id);
604
+ await this.db
605
+ .updateTable("attachments")
606
+ .set({ expires_at: sql `now() + make_interval(hours => ${AGENT_AVATAR_TTL_HOURS})` })
607
+ .where("id", "=", id)
608
+ .where("status", "=", "ready")
609
+ .where("agent_id", "is", null)
610
+ .where("expires_at", "is not", null)
611
+ .execute();
612
+ }
613
+ /**
614
+ * In the caller's transaction, binds a ready avatar upload to `agentId` (row lock; the expiry is
615
+ * cleared, so the cleanup job keeps it while the profile uses it). An upload another agent
616
+ * already uses, or one that is not the account's ready avatar → `attachment.not_found`; saving
617
+ * the same upload to the same agent again is fine.
618
+ */
619
+ async consumeAgentAvatar(orgId, accountId, id, agentId) {
620
+ const trx = this.db.db;
621
+ const row = await trx
622
+ .selectFrom("attachments")
623
+ .select(["status", "agent_id"])
624
+ .where("id", "=", id)
625
+ .where("org_id", "=", orgId)
626
+ .where("account_id", "=", accountId)
627
+ .where("purpose", "=", "agent-avatar")
628
+ .forUpdate()
629
+ .executeTakeFirst();
630
+ if (row?.status !== "ready" || (row.agent_id !== null && row.agent_id !== agentId)) {
631
+ throw notFound();
632
+ }
633
+ await trx
634
+ .updateTable("attachments")
635
+ .set({ agent_id: agentId, expires_at: null })
636
+ .where("id", "=", id)
637
+ .execute();
638
+ }
639
+ /**
640
+ * A short-lived presigned GET (inline, with the checked image type) of the avatar upload bound
641
+ * to `agentId`; `null` when there is none or its object is gone or no longer the finalized one.
642
+ */
643
+ async agentAvatarUrl(orgId, agentId, id) {
644
+ this.storage.assertAvailable();
645
+ const row = await this.db
646
+ .selectFrom("attachments")
647
+ .select(["content_type", "object_key", "etag"])
648
+ .where("id", "=", id)
649
+ .where("org_id", "=", orgId)
650
+ .where("agent_id", "=", agentId)
651
+ .where("purpose", "=", "agent-avatar")
652
+ .where("status", "=", "ready")
653
+ .executeTakeFirst();
654
+ if (!row)
655
+ return null;
656
+ const store = this.storage.kernel(orgId);
657
+ const head = await store.head(row.object_key);
658
+ if (!head || !this.sameContent(row.etag, head.etag, { orgId, attachmentId: id }))
659
+ return null;
660
+ return store.presignGet(row.object_key, {
661
+ ttlSeconds: AGENT_AVATAR_DOWNLOAD_TTL_SECONDS,
662
+ disposition: "inline",
663
+ responseContentType: row.content_type,
664
+ });
665
+ }
544
666
  /**
545
667
  * 删除过期(`expires_at < now()`)且从未绑定到会话的附件:先把行认领为 `deleting`(`FOR UPDATE SKIP LOCKED`,
546
668
  * 多副本并发时互不重复),再删对象、删行。删对象失败的行保持 `deleting`,下次运行重试。
@@ -613,6 +735,9 @@ __decorate([
613
735
  __decorate([
614
736
  Transactional({ propagation: "mandatory" })
615
737
  ], AttachmentsService.prototype, "consumeSkillPackage", null);
738
+ __decorate([
739
+ Transactional({ propagation: "mandatory" })
740
+ ], AttachmentsService.prototype, "consumeAgentAvatar", null);
616
741
  AttachmentsService = __decorate([
617
742
  Injectable(),
618
743
  __param(0, Inject(KernelDb)),
@@ -12,11 +12,27 @@ import type { QueueItem, QueuePauseReason } from "./queue.js";
12
12
  import { ConversationQueue } from "./queue.service.js";
13
13
  import { ConversationSandboxStatus, type SandboxStatusView } from "./sandbox-status.js";
14
14
  declare const ListQuery: z.ZodObject<{
15
+ q: z.ZodOptional<z.ZodString>;
16
+ state: z.ZodOptional<z.ZodEnum<{
17
+ running: "running";
18
+ waiting: "waiting";
19
+ }>>;
20
+ archived: z.ZodOptional<z.ZodEnum<{
21
+ 1: "1";
22
+ }>>;
15
23
  after: z.ZodOptional<z.ZodString>;
16
24
  limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
17
25
  agentId: z.ZodOptional<z.ZodString>;
18
26
  }, z.core.$strip>;
19
27
  declare const GroupsQuery: z.ZodObject<{
28
+ q: z.ZodOptional<z.ZodString>;
29
+ state: z.ZodOptional<z.ZodEnum<{
30
+ running: "running";
31
+ waiting: "waiting";
32
+ }>>;
33
+ archived: z.ZodOptional<z.ZodEnum<{
34
+ 1: "1";
35
+ }>>;
20
36
  perGroup: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
21
37
  limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
22
38
  after: z.ZodOptional<z.ZodString>;
@@ -142,9 +158,13 @@ declare const QueueEditBody: z.ZodObject<{
142
158
  * A rename: 1–120 characters counted in code points after trimming, with no control or format
143
159
  * (bidi, zero-width) characters, the same rule generated and tool titles follow.
144
160
  */
145
- declare const RenameBody: z.ZodObject<{
146
- title: z.ZodString;
161
+ declare const PatchBody: z.ZodObject<{
162
+ title: z.ZodOptional<z.ZodString>;
163
+ archived: z.ZodOptional<z.ZodBoolean>;
147
164
  }, z.core.$strict>;
165
+ declare const IdParams: z.ZodObject<{
166
+ id: z.ZodString;
167
+ }, z.core.$strip>;
148
168
  /**
149
169
  * 会话(`/api/v1/orgs/:orgId/conversations`):`agents.use`(访客以上),只接受人类用户;
150
170
  * 服务令牌 → 403 `forbidden`。只有会话所有者可见,其他人一律 `conversation.not_found`。
@@ -158,15 +178,25 @@ export declare class ConversationsController {
158
178
  private readonly queue;
159
179
  private readonly files;
160
180
  constructor(conversations: ConversationsService, outputs: ConversationOutputs, artifacts: ConversationArtifacts, sandboxStatus: ConversationSandboxStatus, toolInfo: ConversationToolInfo, queue: ConversationQueue, files: ConversationFiles);
161
- /** 201 when created; 200 when `message.clientMessageId` repeats an earlier first send. */
181
+ /**
182
+ * 201 when created; 200 when `message.clientMessageId` repeats an earlier first send. With a
183
+ * message the answer has `event` (the `user_message`) and `events`: every event the first send
184
+ * wrote, in seq order from seq 1 (a `model_switched` first when it switched).
185
+ */
162
186
  create(principal: Principal, org: OrgContext, body: z.infer<typeof CreateBody>, reply: FastifyReply): Promise<{
163
187
  conversation: ConversationView;
164
188
  event?: ConversationEvent;
189
+ events?: ConversationEvent[];
165
190
  }>;
166
- /** Rename (owner only): `titleSource` becomes `manual` and the title is never regenerated. */
167
- rename(principal: Principal, org: OrgContext, id: string, body: z.infer<typeof RenameBody>): Promise<{
191
+ /**
192
+ * Rename and / or archive (owner only). A rename makes `titleSource` `manual`, so the title is
193
+ * never regenerated; `archived` archives or unarchives. Returns the final view.
194
+ */
195
+ patch(principal: Principal, org: OrgContext, id: string, body: z.infer<typeof PatchBody>): Promise<{
168
196
  conversation: ConversationView;
169
197
  }>;
198
+ /** Soft delete (owner only): stops an active run and hides the conversation everywhere. */
199
+ remove(principal: Principal, org: OrgContext, { id }: z.infer<typeof IdParams>): Promise<void>;
170
200
  /** 我的会话,最近更新的在前:`next` 为下一页游标(作为 `after` 传回),没有更多时为 null。 */
171
201
  list(principal: Principal, org: OrgContext, q: z.infer<typeof ListQuery>): Promise<{
172
202
  conversations: ConversationView[];
@@ -180,6 +210,7 @@ export declare class ConversationsController {
180
210
  groups(principal: Principal, org: OrgContext, q: z.infer<typeof GroupsQuery>): Promise<{
181
211
  groups: ConversationGroup[];
182
212
  next: string | null;
213
+ archivedCount: number;
183
214
  }>;
184
215
  get(principal: Principal, org: OrgContext, id: string): Promise<{
185
216
  conversation: ConversationView;
@@ -12,7 +12,7 @@ import { z } from "zod";
12
12
  import { ModelRef } from "../agents/definition.js";
13
13
  import { CurrentPrincipal, requireUser } from "../identity/principal.js";
14
14
  import { createZodDto } from "../infra/validation/create-zod-dto.js";
15
- import { ZBody, ZQuery } from "../infra/validation/zod-params.js";
15
+ import { ZBody, ZParam, ZQuery } from "../infra/validation/zod-params.js";
16
16
  import { CurrentOrg, OrgAction } from "../orgs/org.guard.js";
17
17
  import { CONTROL_OR_HIDDEN_RE } from "../text.js";
18
18
  import { MAX_ATTACHMENTS } from "../tools/connector-content.js";
@@ -23,17 +23,25 @@ import { ConversationFiles, FILE_CONTENT_MAX_BYTES, FILES_PAGE_MAX, } from "./fi
23
23
  import { ConversationOutputs, OUTPUT_PAGE_MAX_CHARS } from "./outputs-read.js";
24
24
  import { ConversationQueue } from "./queue.service.js";
25
25
  import { ConversationSandboxStatus } from "./sandbox-status.js";
26
+ /** Shared by the list and groups queries: title search, run activity and the archived list. */
27
+ const searchFields = {
28
+ q: z.string().min(1).max(100).optional(),
29
+ state: z.enum(["running", "waiting"]).optional(),
30
+ archived: z.enum(["1"]).optional(),
31
+ };
26
32
  const ListQuery = z.object({
27
33
  after: z.string().min(1).max(100).optional(),
28
34
  limit: z.coerce.number().int().min(1).max(200).default(50),
29
35
  /** Only this agent's conversations (the sidebar's per-group "More"). */
30
36
  agentId: z.string().min(1).max(100).optional(),
37
+ ...searchFields,
31
38
  });
32
39
  const GroupsQuery = z.object({
33
40
  perGroup: z.coerce.number().int().min(1).max(20).default(5),
34
41
  limit: z.coerce.number().int().min(1).max(50).default(20),
35
42
  /** The last group's agent id from the previous page (`next`). */
36
43
  after: z.string().min(1).max(100).optional(),
44
+ ...searchFields,
37
45
  });
38
46
  const SubagentsQuery = z.object({
39
47
  /** The previous page's last sub-agent id (`next`). */
@@ -143,7 +151,7 @@ const QueueEditBody = z.object({ text: z.string().max(100_000) }).strict();
143
151
  * A rename: 1–120 characters counted in code points after trimming, with no control or format
144
152
  * (bidi, zero-width) characters, the same rule generated and tool titles follow.
145
153
  */
146
- const RenameBody = z
154
+ const PatchBody = z
147
155
  .object({
148
156
  title: z
149
157
  .string()
@@ -151,12 +159,19 @@ const RenameBody = z
151
159
  .trim()
152
160
  .refine((t) => t.length > 0, "title must not be empty")
153
161
  .refine((t) => Array.from(t).length <= CONVERSATION_TITLE_MAX_CHARS, `title must be at most ${CONVERSATION_TITLE_MAX_CHARS} characters`)
154
- .refine((t) => !CONTROL_OR_HIDDEN_RE.test(t), "title must not contain control or format characters"),
162
+ .refine((t) => !CONTROL_OR_HIDDEN_RE.test(t), "title must not contain control or format characters")
163
+ .optional(),
164
+ /** true archives (hidden from the default lists), false unarchives. */
165
+ archived: z.boolean().optional(),
155
166
  })
156
- .strict();
167
+ .strict()
168
+ .refine((b) => b.title !== undefined || b.archived !== undefined, "title or archived is required");
169
+ const IdParams = z.object({ id: z.string().min(1).max(100) });
157
170
  class ConversationCreateBodyDto extends createZodDto(CreateBody, "ConversationCreateBody") {
158
171
  }
159
- class ConversationRenameBodyDto extends createZodDto(RenameBody, "ConversationRenameBody") {
172
+ class ConversationPatchBodyDto extends createZodDto(PatchBody, "ConversationPatchBody") {
173
+ }
174
+ class ConversationIdParamsDto extends createZodDto(IdParams, "ConversationIdParams") {
160
175
  }
161
176
  class ConversationListQueryDto extends createZodDto(ListQuery, "ConversationListQuery") {
162
177
  }
@@ -203,7 +218,11 @@ let ConversationsController = class ConversationsController {
203
218
  this.queue = queue;
204
219
  this.files = files;
205
220
  }
206
- /** 201 when created; 200 when `message.clientMessageId` repeats an earlier first send. */
221
+ /**
222
+ * 201 when created; 200 when `message.clientMessageId` repeats an earlier first send. With a
223
+ * message the answer has `event` (the `user_message`) and `events`: every event the first send
224
+ * wrote, in seq order from seq 1 (a `model_switched` first when it switched).
225
+ */
207
226
  async create(principal, org, body, reply) {
208
227
  const p = requireUser(principal);
209
228
  if (body.message === undefined) {
@@ -222,15 +241,32 @@ let ConversationsController = class ConversationsController {
222
241
  ...(m.skill !== undefined && { skill: m.skill }),
223
242
  });
224
243
  reply.status(out.created ? 201 : 200);
225
- return { conversation: out.conversation, event: out.event };
244
+ return { conversation: out.conversation, event: out.event, events: out.events };
226
245
  }
227
- /** Rename (owner only): `titleSource` becomes `manual` and the title is never regenerated. */
228
- async rename(principal, org, id, body) {
246
+ /**
247
+ * Rename and / or archive (owner only). A rename makes `titleSource` `manual`, so the title is
248
+ * never regenerated; `archived` archives or unarchives. Returns the final view.
249
+ */
250
+ async patch(principal, org, id, body) {
229
251
  const p = requireUser(principal);
252
+ const renamed = body.title === undefined
253
+ ? undefined
254
+ : await this.conversations.rename(org.orgId, id, p.account.id, body.title);
255
+ if (body.archived === undefined) {
256
+ // The refine guarantees a title when there is no `archived`
257
+ return {
258
+ conversation: renamed ?? (await this.conversations.get(org.orgId, id, p.account.id)),
259
+ };
260
+ }
230
261
  return {
231
- conversation: await this.conversations.rename(org.orgId, id, p.account.id, body.title),
262
+ conversation: await this.conversations.setArchived(org.orgId, id, p.account.id, body.archived),
232
263
  };
233
264
  }
265
+ /** Soft delete (owner only): stops an active run and hides the conversation everywhere. */
266
+ async remove(principal, org, { id }) {
267
+ const p = requireUser(principal);
268
+ await this.conversations.remove(org.orgId, id, p.account.id);
269
+ }
234
270
  /** 我的会话,最近更新的在前:`next` 为下一页游标(作为 `after` 传回),没有更多时为 null。 */
235
271
  async list(principal, org, q) {
236
272
  const p = requireUser(principal);
@@ -238,6 +274,9 @@ let ConversationsController = class ConversationsController {
238
274
  limit: q.limit + 1,
239
275
  ...(q.after !== undefined && { after: q.after }),
240
276
  ...(q.agentId !== undefined && { agentId: q.agentId }),
277
+ ...(q.q !== undefined && { q: q.q }),
278
+ ...(q.state !== undefined && { state: q.state }),
279
+ ...(q.archived !== undefined && { archived: true }),
241
280
  });
242
281
  const conversations = rows.slice(0, q.limit);
243
282
  const next = rows.length > q.limit ? (conversations.at(-1)?.id ?? null) : null;
@@ -254,6 +293,9 @@ let ConversationsController = class ConversationsController {
254
293
  perGroup: q.perGroup,
255
294
  limit: q.limit,
256
295
  ...(q.after !== undefined && { after: q.after }),
296
+ ...(q.q !== undefined && { q: q.q }),
297
+ ...(q.state !== undefined && { state: q.state }),
298
+ ...(q.archived !== undefined && { archived: true }),
257
299
  });
258
300
  }
259
301
  async get(principal, org, id) {
@@ -443,8 +485,16 @@ __decorate([
443
485
  __param(0, CurrentPrincipal()),
444
486
  __param(1, CurrentOrg()),
445
487
  __param(2, Param("id")),
446
- __param(3, ZBody(ConversationRenameBodyDto))
447
- ], ConversationsController.prototype, "rename", null);
488
+ __param(3, ZBody(ConversationPatchBodyDto))
489
+ ], ConversationsController.prototype, "patch", null);
490
+ __decorate([
491
+ Delete(":id"),
492
+ HttpCode(204),
493
+ OrgAction("agents.use"),
494
+ __param(0, CurrentPrincipal()),
495
+ __param(1, CurrentOrg()),
496
+ __param(2, ZParam(ConversationIdParamsDto))
497
+ ], ConversationsController.prototype, "remove", null);
448
498
  __decorate([
449
499
  Get(),
450
500
  OrgAction("agents.use"),
@@ -6,6 +6,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  };
7
7
  import { Module } from "@nestjs/common";
8
8
  import { AgentLookupModule } from "../agents/agent-lookup.js";
9
+ import { BackgroundModule } from "../background/background.module.js";
9
10
  import { ProvidersModule } from "../runtime/providers.js";
10
11
  import { RuntimeModule } from "../runtime/runtime.module.js";
11
12
  import { SandboxModule } from "../sandbox/sandbox.module.js";
@@ -44,6 +45,8 @@ ConversationsModule = __decorate([
44
45
  ProvidersModule,
45
46
  // the sandbox status
46
47
  SandboxModule,
48
+ // the stop of a deleted conversation's background tasks
49
+ BackgroundModule,
47
50
  ],
48
51
  providers: [
49
52
  ConversationsService,