@capybara-hq/kernel 0.1.0-rc.5 → 0.1.0-rc.7

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 (362) hide show
  1. package/bootstrap.json +27 -3
  2. package/dist/admin/admin.controller.d.ts +21 -74
  3. package/dist/admin/admin.controller.js +50 -50
  4. package/dist/admin/admin.schemas.d.ts +57 -0
  5. package/dist/admin/admin.schemas.js +50 -0
  6. package/dist/admin/extensions.controller.d.ts +10 -0
  7. package/dist/admin/extensions.controller.js +18 -0
  8. package/dist/admin/extensions.schemas.d.ts +7 -0
  9. package/dist/admin/extensions.schemas.js +10 -0
  10. package/dist/admin/limit-defaults.d.ts +20 -0
  11. package/dist/admin/limit-defaults.js +10 -0
  12. package/dist/agents/agent-profile.service.d.ts +7 -5
  13. package/dist/agents/agent-profile.service.js +14 -9
  14. package/dist/agents/agents.controller.d.ts +7 -287
  15. package/dist/agents/agents.controller.js +7 -67
  16. package/dist/agents/agents.schemas.d.ts +389 -0
  17. package/dist/agents/agents.schemas.js +126 -0
  18. package/dist/agents/agents.service.d.ts +16 -6
  19. package/dist/agents/agents.service.js +75 -19
  20. package/dist/agents/definition.d.ts +47 -19
  21. package/dist/agents/definition.js +119 -38
  22. package/dist/agents/from-template.d.ts +2 -2
  23. package/dist/agents/from-template.js +76 -45
  24. package/dist/agents/from-template.service.d.ts +12 -0
  25. package/dist/agents/from-template.service.js +23 -6
  26. package/dist/agents/models.controller.d.ts +33 -5
  27. package/dist/agents/models.controller.js +50 -6
  28. package/dist/agents/org-templates.d.ts +13 -3
  29. package/dist/agents/org-templates.js +69 -28
  30. package/dist/agents/pending-connector-requests.d.ts +2 -0
  31. package/dist/agents/pending-connector-requests.js +1 -1
  32. package/dist/agents/pending-connectors.controller.d.ts +1 -1
  33. package/dist/agents/pending-connectors.controller.js +2 -2
  34. package/dist/agents/pending-connectors.service.d.ts +2 -2
  35. package/dist/agents/pending-connectors.service.js +19 -19
  36. package/dist/agents/profile.d.ts +18 -0
  37. package/dist/agents/profile.js +5 -1
  38. package/dist/agents/readiness.controller.d.ts +5 -5
  39. package/dist/agents/readiness.controller.js +6 -6
  40. package/dist/agents/templates.controller.d.ts +8 -17
  41. package/dist/agents/templates.controller.js +13 -31
  42. package/dist/agents/templates.schemas.d.ts +20 -0
  43. package/dist/agents/templates.schemas.js +45 -0
  44. package/dist/background/background.controller.js +3 -2
  45. package/dist/background/background.schemas.d.ts +10 -0
  46. package/dist/background/background.schemas.js +16 -0
  47. package/dist/background/tasks.service.d.ts +1 -1
  48. package/dist/background/tasks.service.js +7 -2
  49. package/dist/catalog/admin-catalog.controller.d.ts +4 -57
  50. package/dist/catalog/admin-catalog.controller.js +8 -45
  51. package/dist/catalog/admin-catalog.schemas.d.ts +72 -0
  52. package/dist/catalog/admin-catalog.schemas.js +92 -0
  53. package/dist/catalog/catalog-content.d.ts +12 -2
  54. package/dist/catalog/catalog-scope.service.js +8 -2
  55. package/dist/catalog/catalog.service.d.ts +2 -0
  56. package/dist/catalog/catalog.service.js +3 -0
  57. package/dist/catalog/component-scope.controller.d.ts +3 -65
  58. package/dist/catalog/component-scope.controller.js +3 -56
  59. package/dist/catalog/component-scope.schemas.d.ts +114 -0
  60. package/dist/catalog/component-scope.schemas.js +97 -0
  61. package/dist/catalog/component-scope.service.d.ts +28 -4
  62. package/dist/catalog/component-scope.service.js +55 -3
  63. package/dist/catalog/component-state.d.ts +9 -2
  64. package/dist/catalog/component-state.js +22 -13
  65. package/dist/catalog/marketplaces.controller.d.ts +5 -35
  66. package/dist/catalog/marketplaces.controller.js +6 -34
  67. package/dist/catalog/marketplaces.schemas.d.ts +48 -0
  68. package/dist/catalog/marketplaces.schemas.js +53 -0
  69. package/dist/catalog/marketplaces.service.d.ts +15 -1
  70. package/dist/catalog/marketplaces.service.js +22 -1
  71. package/dist/catalog/org-catalog.controller.d.ts +6 -62
  72. package/dist/catalog/org-catalog.controller.js +12 -66
  73. package/dist/catalog/org-catalog.schemas.d.ts +79 -0
  74. package/dist/catalog/org-catalog.schemas.js +82 -0
  75. package/dist/catalog/org-catalog.service.d.ts +9 -2
  76. package/dist/catalog/org-catalog.service.js +38 -5
  77. package/dist/catalog/org-extension.controller.d.ts +1 -12
  78. package/dist/catalog/org-extension.controller.js +1 -10
  79. package/dist/catalog/org-extension.schemas.d.ts +15 -0
  80. package/dist/catalog/org-extension.schemas.js +22 -0
  81. package/dist/catalog/org-plugin-uploads.controller.d.ts +2 -19
  82. package/dist/catalog/org-plugin-uploads.controller.js +15 -28
  83. package/dist/catalog/org-plugin-uploads.schemas.d.ts +20 -0
  84. package/dist/catalog/org-plugin-uploads.schemas.js +32 -0
  85. package/dist/catalog/owned-items.d.ts +6 -2
  86. package/dist/catalog/owned-items.js +16 -4
  87. package/dist/catalog/platform-components.d.ts +2 -0
  88. package/dist/catalog/platform-components.js +2 -0
  89. package/dist/catalog/plugin-import.js +1 -0
  90. package/dist/catalog/plugin-install.js +1 -1
  91. package/dist/catalog/requests.service.d.ts +2 -1
  92. package/dist/catalog/requests.service.js +6 -2
  93. package/dist/channels/channels.schemas.d.ts +33 -0
  94. package/dist/channels/channels.schemas.js +34 -0
  95. package/dist/channels/connections.controller.d.ts +2 -29
  96. package/dist/channels/connections.controller.js +1 -23
  97. package/dist/channels/connections.service.d.ts +8 -2
  98. package/dist/channels/connections.service.js +23 -5
  99. package/dist/channels/inbound.js +4 -0
  100. package/dist/config/schema.d.ts +4 -0
  101. package/dist/config/schema.js +24 -0
  102. package/dist/conversations/conversations.controller.d.ts +16 -37
  103. package/dist/conversations/conversations.controller.js +16 -56
  104. package/dist/conversations/conversations.schemas.d.ts +52 -0
  105. package/dist/conversations/conversations.schemas.js +79 -0
  106. package/dist/conversations/conversations.service.d.ts +13 -4
  107. package/dist/conversations/conversations.service.js +32 -26
  108. package/dist/conversations/events.d.ts +80 -6
  109. package/dist/conversations/events.js +60 -5
  110. package/dist/conversations/message-context.d.ts +28 -0
  111. package/dist/conversations/message-context.js +56 -0
  112. package/dist/conversations/queue.d.ts +2 -1
  113. package/dist/conversations/queue.js +11 -2
  114. package/dist/ctx/create-ctx.d.ts +15 -1
  115. package/dist/ctx/create-ctx.js +23 -2
  116. package/dist/db/kernel-schema.d.ts +44 -0
  117. package/dist/environments/environments.schemas.d.ts +3 -0
  118. package/dist/environments/environments.schemas.js +14 -0
  119. package/dist/environments/environments.service.d.ts +16 -4
  120. package/dist/environments/environments.service.js +58 -13
  121. package/dist/errors.d.ts +6 -0
  122. package/dist/errors.js +6 -0
  123. package/dist/evals/evals.schemas.d.ts +110 -0
  124. package/dist/evals/evals.schemas.js +107 -0
  125. package/dist/evals/reconstruct.js +18 -11
  126. package/dist/evals/recorded-tools.d.ts +2 -1
  127. package/dist/evals/recorded-tools.js +11 -3
  128. package/dist/evals/run-replay.d.ts +8 -1
  129. package/dist/evals/run-replay.js +17 -2
  130. package/dist/evals/runs.controller.d.ts +2 -57
  131. package/dist/evals/runs.controller.js +1 -42
  132. package/dist/evals/runs.service.d.ts +8 -7
  133. package/dist/evals/runs.service.js +45 -30
  134. package/dist/evals/sets.controller.d.ts +2 -28
  135. package/dist/evals/sets.controller.js +1 -31
  136. package/dist/evals/sets.service.d.ts +7 -7
  137. package/dist/evals/sets.service.js +23 -17
  138. package/dist/evals/snapshot.d.ts +3 -2
  139. package/dist/evals/snapshot.js +17 -4
  140. package/dist/evals/step-replay.d.ts +2 -1
  141. package/dist/evals/step-replay.js +3 -2
  142. package/dist/extensions/admin-ops.d.ts +5 -3
  143. package/dist/extensions/admin-ops.js +17 -12
  144. package/dist/extensions/config-hash.d.ts +10 -0
  145. package/dist/extensions/config-hash.js +38 -0
  146. package/dist/extensions/deployment-config.d.ts +16 -1
  147. package/dist/extensions/deployment-config.js +83 -0
  148. package/dist/extensions/extensions.module.js +9 -12
  149. package/dist/extensions/host.d.ts +39 -12
  150. package/dist/extensions/host.js +129 -51
  151. package/dist/extensions/installs.d.ts +5 -0
  152. package/dist/extensions/installs.js +12 -0
  153. package/dist/extensions/org-config.d.ts +17 -2
  154. package/dist/extensions/org-config.js +23 -4
  155. package/dist/extensions/point-defaults.controller.d.ts +2 -8
  156. package/dist/extensions/point-defaults.controller.js +1 -3
  157. package/dist/extensions/point-defaults.d.ts +3 -1
  158. package/dist/extensions/point-defaults.js +4 -2
  159. package/dist/extensions/point-defaults.schemas.d.ts +9 -0
  160. package/dist/extensions/point-defaults.schemas.js +14 -0
  161. package/dist/extensions/state.module.d.ts +9 -0
  162. package/dist/extensions/state.module.js +38 -0
  163. package/dist/extensions/unavailable.d.ts +49 -0
  164. package/dist/extensions/unavailable.js +113 -0
  165. package/dist/files/previewers.controller.js +2 -3
  166. package/dist/files/previewers.d.ts +1 -1
  167. package/dist/files/previewers.js +4 -4
  168. package/dist/files/previewers.schemas.d.ts +10 -0
  169. package/dist/files/previewers.schemas.js +9 -0
  170. package/dist/http/api.module.js +4 -0
  171. package/dist/http/plugin-dispatch.d.ts +4 -1
  172. package/dist/http/plugin-dispatch.js +14 -2
  173. package/dist/identity/accounts.d.ts +43 -4
  174. package/dist/identity/accounts.js +74 -6
  175. package/dist/identity/auth.guard.js +10 -1
  176. package/dist/identity/cookies.d.ts +6 -0
  177. package/dist/identity/cookies.js +14 -0
  178. package/dist/identity/identity.module.js +3 -0
  179. package/dist/identity/initial-passwords.controller.d.ts +22 -0
  180. package/dist/identity/initial-passwords.controller.js +49 -0
  181. package/dist/identity/initial-passwords.d.ts +61 -0
  182. package/dist/identity/initial-passwords.job.d.ts +16 -0
  183. package/dist/identity/initial-passwords.job.js +46 -0
  184. package/dist/identity/initial-passwords.js +159 -0
  185. package/dist/identity/me.controller.d.ts +14 -0
  186. package/dist/identity/me.controller.js +39 -1
  187. package/dist/identity/principal.d.ts +8 -0
  188. package/dist/identity/principal.js +8 -0
  189. package/dist/identity/settings.d.ts +3 -1
  190. package/dist/identity/settings.js +6 -4
  191. package/dist/inbox/inbox.schemas.d.ts +8 -0
  192. package/dist/inbox/inbox.schemas.js +11 -0
  193. package/dist/inbox/platform-inbox.controller.d.ts +1 -1
  194. package/dist/inbox/platform-inbox.controller.js +2 -2
  195. package/dist/index.d.ts +4 -0
  196. package/dist/index.js +6 -0
  197. package/dist/infra/config/kernel-config.service.js +3 -0
  198. package/dist/infra/events/kernel-events.d.ts +8 -0
  199. package/dist/lifecycle/kernel-lifecycle.js +4 -0
  200. package/dist/models/embeddings.d.ts +82 -0
  201. package/dist/models/embeddings.js +326 -0
  202. package/dist/models/enablement.controller.d.ts +40 -0
  203. package/dist/models/enablement.controller.js +74 -0
  204. package/dist/models/enablement.d.ts +101 -0
  205. package/dist/models/enablement.js +264 -0
  206. package/dist/models/models.module.d.ts +5 -1
  207. package/dist/models/models.module.js +16 -4
  208. package/dist/models/org-models.schemas.d.ts +8 -0
  209. package/dist/models/org-models.schemas.js +22 -0
  210. package/dist/models/prices.d.ts +3 -1
  211. package/dist/models/prices.js +7 -5
  212. package/dist/models/purposes.d.ts +30 -6
  213. package/dist/models/purposes.js +68 -17
  214. package/dist/orgs/orgs.controller.d.ts +2 -5
  215. package/dist/orgs/orgs.controller.js +3 -6
  216. package/dist/orgs/orgs.schemas.d.ts +8 -0
  217. package/dist/orgs/orgs.schemas.js +16 -0
  218. package/dist/orgs/orgs.service.d.ts +3 -1
  219. package/dist/orgs/orgs.service.js +6 -4
  220. package/dist/orgs/settings.service.d.ts +9 -1
  221. package/dist/orgs/settings.service.js +20 -5
  222. package/dist/overrides.d.ts +4 -0
  223. package/dist/overrides.js +2 -0
  224. package/dist/platform/errors.d.ts +21 -4
  225. package/dist/platform/errors.js +45 -6
  226. package/dist/platform/exclusions.d.ts +2 -3
  227. package/dist/platform/exclusions.js +68 -831
  228. package/dist/platform/method.js +1 -1
  229. package/dist/platform/operation.d.ts +82 -5
  230. package/dist/platform/operation.js +62 -7
  231. package/dist/platform/ops/accounts.ops.d.ts +32 -0
  232. package/dist/platform/ops/accounts.ops.js +291 -0
  233. package/dist/platform/ops/admin.ops.d.ts +36 -0
  234. package/dist/platform/ops/admin.ops.js +389 -0
  235. package/dist/platform/ops/agent-skills.ops.d.ts +24 -0
  236. package/dist/platform/ops/agent-skills.ops.js +226 -0
  237. package/dist/platform/ops/agent-templates.ops.d.ts +4 -1
  238. package/dist/platform/ops/agent-templates.ops.js +194 -14
  239. package/dist/platform/ops/agents.ops.d.ts +19 -1
  240. package/dist/platform/ops/agents.ops.js +481 -58
  241. package/dist/platform/ops/approvals.ops.d.ts +30 -0
  242. package/dist/platform/ops/approvals.ops.js +116 -0
  243. package/dist/platform/ops/background.ops.d.ts +14 -0
  244. package/dist/platform/ops/background.ops.js +134 -0
  245. package/dist/platform/ops/catalog-admin.ops.d.ts +74 -0
  246. package/dist/platform/ops/catalog-admin.ops.js +587 -0
  247. package/dist/platform/ops/channels.ops.d.ts +16 -0
  248. package/dist/platform/ops/channels.ops.js +195 -0
  249. package/dist/platform/ops/components.ops.d.ts +46 -0
  250. package/dist/platform/ops/components.ops.js +853 -0
  251. package/dist/platform/ops/connectors.ops.d.ts +4 -2
  252. package/dist/platform/ops/connectors.ops.js +68 -6
  253. package/dist/platform/ops/conversations.ops.d.ts +30 -0
  254. package/dist/platform/ops/conversations.ops.js +470 -0
  255. package/dist/platform/ops/environments.ops.d.ts +26 -0
  256. package/dist/platform/ops/environments.ops.js +289 -0
  257. package/dist/platform/ops/errors.d.ts +10 -5
  258. package/dist/platform/ops/errors.js +19 -11
  259. package/dist/platform/ops/evals.ops.d.ts +28 -0
  260. package/dist/platform/ops/evals.ops.js +783 -0
  261. package/dist/platform/ops/extensions-admin.ops.d.ts +25 -0
  262. package/dist/platform/ops/extensions-admin.ops.js +344 -0
  263. package/dist/platform/ops/extensions.ops.d.ts +7 -1
  264. package/dist/platform/ops/extensions.ops.js +248 -17
  265. package/dist/platform/ops/inbox.ops.d.ts +25 -0
  266. package/dist/platform/ops/inbox.ops.js +378 -0
  267. package/dist/platform/ops/marketplaces.ops.d.ts +7 -1
  268. package/dist/platform/ops/marketplaces.ops.js +326 -17
  269. package/dist/platform/ops/models.ops.d.ts +25 -0
  270. package/dist/platform/ops/models.ops.js +232 -0
  271. package/dist/platform/ops/org-plugins.ops.d.ts +29 -0
  272. package/dist/platform/ops/org-plugins.ops.js +329 -0
  273. package/dist/platform/ops/org-settings.ops.d.ts +16 -0
  274. package/dist/platform/ops/org-settings.ops.js +102 -0
  275. package/dist/platform/ops/orgs.ops.d.ts +28 -0
  276. package/dist/platform/ops/orgs.ops.js +295 -0
  277. package/dist/platform/ops/other-orgs.d.ts +20 -0
  278. package/dist/platform/ops/other-orgs.js +72 -0
  279. package/dist/platform/ops/platform.ops.d.ts +4 -4
  280. package/dist/platform/ops/platform.ops.js +23 -24
  281. package/dist/platform/ops/plugins.ops.d.ts +10 -8
  282. package/dist/platform/ops/plugins.ops.js +176 -77
  283. package/dist/platform/ops/previewers.ops.d.ts +14 -0
  284. package/dist/platform/ops/previewers.ops.js +109 -0
  285. package/dist/platform/ops/requests.ops.js +57 -19
  286. package/dist/platform/ops/skills.ops.d.ts +5 -1
  287. package/dist/platform/ops/skills.ops.js +129 -11
  288. package/dist/platform/ops/unavailable.d.ts +23 -0
  289. package/dist/platform/ops/unavailable.js +111 -0
  290. package/dist/platform/parity.d.ts +33 -0
  291. package/dist/platform/parity.js +272 -0
  292. package/dist/platform/platform-ops.module.d.ts +32 -0
  293. package/dist/platform/platform-ops.module.js +78 -11
  294. package/dist/platform/route-schemas.d.ts +18 -0
  295. package/dist/platform/route-schemas.js +60 -0
  296. package/dist/roles/worker.module.js +2 -0
  297. package/dist/runtime/context/build.d.ts +2 -0
  298. package/dist/runtime/context/build.js +28 -2
  299. package/dist/runtime/context/compaction.js +10 -1
  300. package/dist/runtime/context/run-context.d.ts +65 -0
  301. package/dist/runtime/context/run-context.js +215 -0
  302. package/dist/runtime/hook-calls.d.ts +8 -1
  303. package/dist/runtime/hook-calls.js +40 -9
  304. package/dist/runtime/model-call.d.ts +8 -3
  305. package/dist/runtime/model-call.js +30 -6
  306. package/dist/runtime/providers.d.ts +146 -32
  307. package/dist/runtime/providers.js +328 -67
  308. package/dist/runtime/run-context.service.d.ts +65 -0
  309. package/dist/runtime/run-context.service.js +220 -0
  310. package/dist/runtime/run-worker.d.ts +6 -1
  311. package/dist/runtime/run-worker.js +35 -10
  312. package/dist/runtime/runtime.module.js +2 -0
  313. package/dist/runtime/subagents/definition.d.ts +15 -15
  314. package/dist/runtime/subagents/definition.js +49 -118
  315. package/dist/runtime/usage-report-jobs.d.ts +88 -0
  316. package/dist/runtime/usage-report-jobs.js +158 -0
  317. package/dist/runtime/usage-report.d.ts +33 -38
  318. package/dist/runtime/usage-report.js +152 -84
  319. package/dist/skills/changes.controller.js +2 -1
  320. package/dist/skills/changes.service.d.ts +1 -1
  321. package/dist/skills/changes.service.js +4 -4
  322. package/dist/skills/invocable.controller.d.ts +1 -1
  323. package/dist/skills/invocable.controller.js +2 -2
  324. package/dist/skills/invoke.d.ts +2 -2
  325. package/dist/skills/invoke.js +8 -1
  326. package/dist/skills/skills.controller.d.ts +4 -13
  327. package/dist/skills/skills.controller.js +8 -24
  328. package/dist/skills/skills.schemas.d.ts +48 -0
  329. package/dist/skills/skills.schemas.js +61 -0
  330. package/dist/skills/skills.service.d.ts +11 -1
  331. package/dist/skills/skills.service.js +37 -14
  332. package/dist/time-zone.d.ts +5 -0
  333. package/dist/time-zone.js +19 -0
  334. package/dist/tools/approvals.controller.js +2 -3
  335. package/dist/tools/approvals.schemas.d.ts +21 -0
  336. package/dist/tools/approvals.schemas.js +15 -0
  337. package/dist/tools/builtin-names.d.ts +10 -8
  338. package/dist/tools/builtin-names.js +16 -11
  339. package/dist/tools/builtins/builtin-tools.d.ts +3 -1
  340. package/dist/tools/builtins/builtin-tools.js +15 -3
  341. package/dist/tools/builtins/current-time.d.ts +26 -0
  342. package/dist/tools/builtins/current-time.js +99 -0
  343. package/dist/tools/builtins/platform.d.ts +19 -2
  344. package/dist/tools/builtins/platform.js +105 -16
  345. package/dist/tools/connectors.controller.d.ts +1 -2
  346. package/dist/tools/connectors.controller.js +1 -4
  347. package/dist/tools/connectors.schemas.d.ts +12 -0
  348. package/dist/tools/connectors.schemas.js +19 -0
  349. package/dist/tools/connectors.service.d.ts +5 -2
  350. package/dist/tools/connectors.service.js +7 -5
  351. package/dist/tools/org-tool-switches.d.ts +16 -2
  352. package/dist/tools/org-tool-switches.js +26 -9
  353. package/dist/tools/pipeline.js +9 -1
  354. package/dist/tools/registry.d.ts +48 -51
  355. package/dist/tools/registry.js +222 -233
  356. package/package.json +3 -3
  357. package/src/migrations/0089_model_kinds_usage.sql +38 -0
  358. package/src/migrations/0090_initial_passwords.sql +27 -0
  359. package/src/migrations/0091_account_time_zone.sql +4 -0
  360. package/src/migrations/0092_tools_default_on.sql +27 -0
  361. package/dist/platform/redact-orgs.d.ts +0 -7
  362. package/dist/platform/redact-orgs.js +0 -52
@@ -29,6 +29,7 @@ import { readAgentTree } from "./agent-tree.js";
29
29
  import { AttachmentsService } from "./attachments.service.js";
30
30
  import { EventLog } from "./event-log.js";
31
31
  import { userMessageIdemKey } from "./idem-keys.js";
32
+ import { readMessageContext } from "./message-context.js";
32
33
  import { NO_SELECTION, planSelection, readSelection } from "./selection.js";
33
34
  import { conversationTree } from "./tree.js";
34
35
  /** Escapes `\`, `%` and `_` so user text is matched literally by `LIKE … ESCAPE '\'`. */
@@ -205,7 +206,7 @@ let ConversationsService = class ConversationsService {
205
206
  if (prior)
206
207
  return prior;
207
208
  const environmentId = await this.environments.forNew(orgId, accountId, pick);
208
- const next = await this.planSwitch(agent.definition, NO_SELECTION, input);
209
+ const next = await this.planSwitch(orgId, agent.definition, NO_SELECTION, input);
209
210
  const extra = await this.resolveExtra(orgId, accountId, input);
210
211
  const invoked = await this.prepareSkill(orgId, agentId, undefined, agent.definition, input);
211
212
  const id = randomUUID();
@@ -245,7 +246,7 @@ let ConversationsService = class ConversationsService {
245
246
  if (!row)
246
247
  return undefined;
247
248
  const blocks = await this.bindIn(orgId, id, accountId, input.files ?? []);
248
- return this.writeMessage(id, accountId, input, next, extra, blocks, invoked);
249
+ return this.writeMessage(orgId, id, accountId, input, next, extra, blocks, invoked);
249
250
  }
250
251
  /**
251
252
  * The conversation (and its first event) an earlier first send with this id created. The id used
@@ -701,23 +702,17 @@ let ConversationsService = class ConversationsService {
701
702
  : undefined;
702
703
  const next = agent === undefined || (input.model === undefined && input.effort === undefined)
703
704
  ? null
704
- : await this.planSwitch(agent, conv.selection, input);
705
+ : await this.planSwitch(orgId, agent, conv.selection, input);
705
706
  const extra = await this.resolveExtra(orgId, accountId, input);
706
707
  const invoked = agent === undefined
707
708
  ? undefined
708
709
  : await this.prepareSkill(orgId, conv.agentId, conversationId, agent, input);
709
- let event;
710
- if (files.length > 0 || next !== null) {
711
- event = await this.postIn(orgId, conversationId, accountId, input, next, extra, invoked);
712
- await this.eventLog.notify(conversationId, event.seq);
713
- if (next !== null)
714
- await this.eventLog.publishChanged(conversationId, "selection");
715
- }
716
- else {
717
- [event] = await this.eventLog.append(conversationId, [
718
- this.userMessage(accountId, input, extra, [], invoked),
719
- ]);
720
- }
710
+ // one transaction: the sender, time zone and language are read with the message's write
711
+ // (run context spec §3.2)
712
+ const event = await this.postIn(orgId, conversationId, accountId, input, next, extra, invoked);
713
+ await this.eventLog.notify(conversationId, event.seq);
714
+ if (next !== null)
715
+ await this.eventLog.publishChanged(conversationId, "selection");
721
716
  // The message is written: it brings an archived conversation back into the default lists
722
717
  if (conv.archivedAt !== null) {
723
718
  await this.db
@@ -730,27 +725,31 @@ let ConversationsService = class ConversationsService {
730
725
  await this.runs.ensureRun(conversationId);
731
726
  return event;
732
727
  }
733
- /** A message with files or a model switch: binds the files and writes it in one transaction. */
728
+ /**
729
+ * Writes a message in one transaction: binds its files, reads its sender context and appends it
730
+ * (after its `model_switched` when it switches).
731
+ */
734
732
  // its own transaction: the caller notifies and publishes after the commit
735
733
  async postIn(orgId, conversationId, accountId, input, next, extra, invoked) {
736
734
  const blocks = await this.bindIn(orgId, conversationId, accountId, input.files ?? []);
737
- const written = await this.writeMessage(conversationId, accountId, input, next, extra, blocks, invoked);
735
+ const written = await this.writeMessage(orgId, conversationId, accountId, input, next, extra, blocks, invoked);
738
736
  return written.at(-1);
739
737
  }
740
738
  /**
741
739
  * The selection a message switches to, or null when it changes nothing. A model equal to the
742
740
  * agent's means "back to the agent's model" (null); a model change without `effort` resets the
743
741
  * effort. The target model must resolve (`agent.model_unavailable`) and declare the effort
744
- * (`validation_failed`). Resolving is the agent editor's check: providers are deployment-scoped
745
- * and serve chat models only. If per-org provider enablement is added, this check and the run
746
- * worker's `fallBackIfUnavailable` must follow it.
742
+ * (`validation_failed`). Resolving is the agent editor's check, for the org (its effective
743
+ * provider config, spec B §5.5) and its disabled lists: a model the platform or the org disabled,
744
+ * or a non-chat model, is refused (spec B §5.3), as the run worker's `fallBackIfUnavailable` falls
745
+ * back from it.
747
746
  */
748
- async planSwitch(agent, current, input) {
747
+ async planSwitch(orgId, agent, current, input) {
749
748
  const next = planSelection(agent.model, current, input);
750
749
  if (next === null)
751
750
  return null;
752
751
  const { model, effort } = next;
753
- const { info } = await this.providers.resolve(model ?? agent.model);
752
+ const { info } = await this.providers.resolve(orgId, model ?? agent.model);
754
753
  if (effort !== null) {
755
754
  const knob = info.parameters.find((p) => p.key === "effort");
756
755
  const values = knob?.schema?.enum ?? [];
@@ -771,14 +770,14 @@ let ConversationsService = class ConversationsService {
771
770
  if (pick.model === undefined && pick.effort === undefined)
772
771
  return;
773
772
  const agent = await this.agents.get(orgId, conv.agentId, accountId);
774
- await this.planSwitch(agent.definition, conv.selection, pick);
773
+ await this.planSwitch(orgId, agent.definition, conv.selection, pick);
775
774
  }
776
775
  /**
777
776
  * Writes the message (preceded by its `model_switched` when it switches) inside `t` and updates
778
777
  * `conversations.selection`; returns the events written, in seq order (the `user_message`
779
778
  * last). The caller notifies after commit.
780
779
  */
781
- async writeMessage(conversationId, accountId, input, next, extra, blocks, invoked) {
780
+ async writeMessage(orgId, conversationId, accountId, input, next, extra, blocks, invoked) {
782
781
  const events = [];
783
782
  if (next !== null) {
784
783
  events.push({
@@ -789,7 +788,13 @@ let ConversationsService = class ConversationsService {
789
788
  payload: { ...next, byAccountId: accountId, reason: "user" },
790
789
  });
791
790
  }
792
- events.push(this.userMessage(accountId, input, extra, blocks, invoked));
791
+ const context = await readMessageContext(this.db.db, {
792
+ orgId,
793
+ accountId,
794
+ senderName: input.senderName,
795
+ browser: { timeZone: input.timeZone, locale: input.locale },
796
+ });
797
+ events.push(this.userMessage(accountId, input, extra, blocks, invoked, context));
793
798
  const written = await this.eventLog.appendIn(conversationId, events);
794
799
  if (next !== null) {
795
800
  const t = this.db.db;
@@ -846,7 +851,7 @@ let ConversationsService = class ConversationsService {
846
851
  return [];
847
852
  return this.attachments.bindForMessage(orgId, conversationId, accountId, files);
848
853
  }
849
- userMessage(accountId, input, extra, fileBlocks, invoked) {
854
+ userMessage(accountId, input, extra, fileBlocks, invoked, context) {
850
855
  // a skill invocation's rendered text replaces the typed arguments as content[0]
851
856
  const text = invoked?.text ?? input.text;
852
857
  return {
@@ -863,6 +868,7 @@ let ConversationsService = class ConversationsService {
863
868
  ],
864
869
  ...(extra.attachments.length > 0 && { attachments: extra.attachments }),
865
870
  authorAccountId: accountId,
871
+ ...context,
866
872
  ...(input.clientMessageId !== undefined && { clientMessageId: input.clientMessageId }),
867
873
  ...(input.retryOf !== undefined && { retryOf: input.retryOf }),
868
874
  ...(invoked !== undefined && { skill: invoked.skill }),
@@ -145,6 +145,39 @@ export declare const SubagentFinishStatusSchema: z.ZodEnum<{
145
145
  max_steps: "max_steps";
146
146
  timed_out: "timed_out";
147
147
  }>;
148
+ /** The languages a run context names (the org `locale` values). */
149
+ export declare const RUN_CONTEXT_LOCALES: readonly ["zh", "en"];
150
+ /** `user_message.sender` (run context spec §3.2). */
151
+ export declare const MessageSenderSchema: z.ZodObject<{
152
+ name: z.ZodString;
153
+ role: z.ZodOptional<z.ZodEnum<{
154
+ admin: "admin";
155
+ guest: "guest";
156
+ member: "member";
157
+ owner: "owner";
158
+ }>>;
159
+ anonymous: z.ZodOptional<z.ZodLiteral<true>>;
160
+ }, z.core.$strip>;
161
+ /** `run_context` (run context spec §3.1): every field optional, a later event holds changes only. */
162
+ export declare const RunContextSchema: z.ZodObject<{
163
+ agent: z.ZodOptional<z.ZodObject<{
164
+ name: z.ZodString;
165
+ description: z.ZodOptional<z.ZodString>;
166
+ }, z.core.$strip>>;
167
+ org: z.ZodOptional<z.ZodObject<{
168
+ name: z.ZodString;
169
+ }, z.core.$strip>>;
170
+ date: z.ZodOptional<z.ZodString>;
171
+ timeZone: z.ZodOptional<z.ZodString>;
172
+ locale: z.ZodOptional<z.ZodEnum<{
173
+ en: "en";
174
+ zh: "zh";
175
+ }>>;
176
+ dispatchedBy: z.ZodOptional<z.ZodObject<{
177
+ agent: z.ZodString;
178
+ person: z.ZodString;
179
+ }, z.core.$strip>>;
180
+ }, z.core.$strip>;
148
181
  /**
149
182
  * 会话事件(`type` + `payload`)的判别联合。事件日志只追加,写入前用它校验 payload;
150
183
  * 读出时按写入时的形状原样返回。
@@ -217,6 +250,21 @@ export declare const ConversationEventSchema: z.ZodDiscriminatedUnion<[z.ZodObje
217
250
  name: z.ZodString;
218
251
  }, z.core.$strip>>>;
219
252
  authorAccountId: z.ZodString;
253
+ sender: z.ZodOptional<z.ZodObject<{
254
+ name: z.ZodString;
255
+ role: z.ZodOptional<z.ZodEnum<{
256
+ admin: "admin";
257
+ guest: "guest";
258
+ member: "member";
259
+ owner: "owner";
260
+ }>>;
261
+ anonymous: z.ZodOptional<z.ZodLiteral<true>>;
262
+ }, z.core.$strip>>;
263
+ timeZone: z.ZodOptional<z.ZodString>;
264
+ locale: z.ZodOptional<z.ZodEnum<{
265
+ en: "en";
266
+ zh: "zh";
267
+ }>>;
220
268
  clientMessageId: z.ZodOptional<z.ZodString>;
221
269
  retryOf: z.ZodOptional<z.ZodNumber>;
222
270
  skill: z.ZodOptional<z.ZodObject<{
@@ -241,18 +289,18 @@ export declare const ConversationEventSchema: z.ZodDiscriminatedUnion<[z.ZodObje
241
289
  task: "task";
242
290
  }>>;
243
291
  narrowed: z.ZodOptional<z.ZodObject<{
244
- tools: z.ZodArray<z.ZodPreprocess<z.ZodDiscriminatedUnion<[z.ZodObject<{
292
+ disabledTools: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
245
293
  kind: z.ZodLiteral<"builtin">;
246
294
  name: z.ZodString;
247
295
  }, z.core.$strict>, z.ZodObject<{
248
296
  kind: z.ZodLiteral<"plugin">;
249
297
  plugin: z.ZodString;
250
- name: z.ZodString;
298
+ tools: z.ZodUnion<readonly [z.ZodLiteral<"all">, z.ZodArray<z.ZodString>]>;
251
299
  }, z.core.$strict>, z.ZodObject<{
252
300
  kind: z.ZodLiteral<"connector">;
253
301
  connectorId: z.ZodString;
254
302
  tools: z.ZodUnion<readonly [z.ZodLiteral<"all">, z.ZodArray<z.ZodString>]>;
255
- }, z.core.$strict>], "kind">, unknown>>;
303
+ }, z.core.$strict>], "kind">>>;
256
304
  skills: z.ZodOptional<z.ZodObject<{
257
305
  orgSkills: z.ZodArray<z.ZodString>;
258
306
  pinned: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -439,6 +487,27 @@ export declare const ConversationEventSchema: z.ZodDiscriminatedUnion<[z.ZodObje
439
487
  step: z.ZodNumber;
440
488
  text: z.ZodString;
441
489
  }, z.core.$strip>;
490
+ }, z.core.$strip>, z.ZodObject<{
491
+ type: z.ZodLiteral<"run_context">;
492
+ payload: z.ZodObject<{
493
+ agent: z.ZodOptional<z.ZodObject<{
494
+ name: z.ZodString;
495
+ description: z.ZodOptional<z.ZodString>;
496
+ }, z.core.$strip>>;
497
+ org: z.ZodOptional<z.ZodObject<{
498
+ name: z.ZodString;
499
+ }, z.core.$strip>>;
500
+ date: z.ZodOptional<z.ZodString>;
501
+ timeZone: z.ZodOptional<z.ZodString>;
502
+ locale: z.ZodOptional<z.ZodEnum<{
503
+ en: "en";
504
+ zh: "zh";
505
+ }>>;
506
+ dispatchedBy: z.ZodOptional<z.ZodObject<{
507
+ agent: z.ZodString;
508
+ person: z.ZodString;
509
+ }, z.core.$strip>>;
510
+ }, z.core.$strip>;
442
511
  }, z.core.$strip>, z.ZodObject<{
443
512
  type: z.ZodLiteral<"tools_changed">;
444
513
  payload: z.ZodObject<{
@@ -697,6 +766,7 @@ export declare const ConversationEventSchema: z.ZodDiscriminatedUnion<[z.ZodObje
697
766
  }, z.core.$strip>;
698
767
  definition: z.ZodObject<{
699
768
  name: z.ZodString;
769
+ description: z.ZodOptional<z.ZodString>;
700
770
  avatarUrl: z.ZodDefault<z.ZodNullable<z.ZodURL>>;
701
771
  instructions: z.ZodDefault<z.ZodString>;
702
772
  instructionFiles: z.ZodOptional<z.ZodArray<z.ZodObject<{
@@ -713,18 +783,22 @@ export declare const ConversationEventSchema: z.ZodDiscriminatedUnion<[z.ZodObje
713
783
  }, z.core.$strip>>>;
714
784
  modelParams: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
715
785
  fallbackParams: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
716
- tools: z.ZodDefault<z.ZodArray<z.ZodPreprocess<z.ZodDiscriminatedUnion<[z.ZodObject<{
786
+ disabledTools: z.ZodDefault<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
717
787
  kind: z.ZodLiteral<"builtin">;
718
788
  name: z.ZodString;
719
789
  }, z.core.$strict>, z.ZodObject<{
720
790
  kind: z.ZodLiteral<"plugin">;
721
791
  plugin: z.ZodString;
722
- name: z.ZodString;
792
+ tools: z.ZodUnion<readonly [z.ZodLiteral<"all">, z.ZodArray<z.ZodString>]>;
723
793
  }, z.core.$strict>, z.ZodObject<{
724
794
  kind: z.ZodLiteral<"connector">;
725
795
  connectorId: z.ZodString;
726
796
  tools: z.ZodUnion<readonly [z.ZodLiteral<"all">, z.ZodArray<z.ZodString>]>;
727
- }, z.core.$strict>], "kind">, unknown>>>;
797
+ }, z.core.$strict>], "kind">>>;
798
+ subagentTools: z.ZodOptional<z.ZodObject<{
799
+ allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
800
+ deny: z.ZodOptional<z.ZodArray<z.ZodString>>;
801
+ }, z.core.$strict>>;
728
802
  toolPolicies: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodEnum<{
729
803
  ask: "ask";
730
804
  deny: "deny";
@@ -1,6 +1,6 @@
1
1
  import { DOCUMENT_MEDIA_TYPES, hasControlChars, IMAGE_MEDIA_TYPES, isAttachmentId, isSkillName, MEDIA_NAME_MAX_CHARS, } from "@capybara-hq/plugin-sdk";
2
2
  import { z } from "zod";
3
- import { AgentDefinitionSchema, AgentToolRef, ModelRef } from "../agents/definition.js";
3
+ import { AgentDefinitionSchema, DisabledToolRef, ModelRef } from "../agents/definition.js";
4
4
  import { ORG_ROLES } from "../orgs/roles.js";
5
5
  import { TOOL_VIEW_DIFF_MAX_LINES, TOOL_VIEW_LINE_MAX_CHARS, TOOL_VIEW_PATH_MAX_CHARS, } from "../tools/view.js";
6
6
  /** 供应商私有数据(`ProviderOpaque`):原样保存、只回放给同一供应商。 */
@@ -176,6 +176,37 @@ const InputFormSchema = z.object({
176
176
  });
177
177
  /** 表单答案(plugin-sdk 的 `FormAnswer`)。 */
178
178
  const FormAnswerSchema = z.record(z.string(), z.union([z.string(), z.number(), z.boolean(), z.array(z.string())]));
179
+ /** The languages a run context names (the org `locale` values). */
180
+ export const RUN_CONTEXT_LOCALES = ["zh", "en"];
181
+ /** `user_message.sender` (run context spec §3.2). */
182
+ export const MessageSenderSchema = z.object({
183
+ name: z.string().min(1).max(80),
184
+ /** Absent = no membership. */
185
+ role: z.enum(ORG_ROLES).optional(),
186
+ /** An IM sender served as the org's anonymous guest; `name` is the IM profile name. */
187
+ anonymous: z.literal(true).optional(),
188
+ });
189
+ /** `run_context` (run context spec §3.1): every field optional, a later event holds changes only. */
190
+ export const RunContextSchema = z.object({
191
+ /** The agent itself: its name and its versioned description collapsed to one line. */
192
+ agent: z
193
+ .object({ name: z.string().min(1).max(130), description: z.string().max(200).optional() })
194
+ .optional(),
195
+ org: z.object({ name: z.string().min(1).max(200) }).optional(),
196
+ /** Today in `timeZone`, `YYYY-MM-DD`. */
197
+ date: z
198
+ .string()
199
+ .regex(/^\d{4}-\d{2}-\d{2}$/)
200
+ .optional(),
201
+ /** IANA name. */
202
+ timeZone: z.string().min(1).max(64).optional(),
203
+ /** The language of the person whose message started the run. */
204
+ locale: z.enum(RUN_CONTEXT_LOCALES).optional(),
205
+ /** Sub-agents only: who dispatched this conversation. */
206
+ dispatchedBy: z
207
+ .object({ agent: z.string().min(1).max(130), person: z.string().min(1).max(80) })
208
+ .optional(),
209
+ });
179
210
  const ev = (type, payload) => z.object({ type: z.literal(type), payload });
180
211
  /**
181
212
  * 会话事件(`type` + `payload`)的判别联合。事件日志只追加,写入前用它校验 payload;
@@ -193,6 +224,20 @@ export const ConversationEventSchema = z.discriminatedUnion("type", [
193
224
  .array(z.object({ appId: z.string(), appName: z.string(), uri: z.string(), name: z.string() }))
194
225
  .optional(),
195
226
  authorAccountId: z.string(),
227
+ /**
228
+ * Who wrote the message, at send time (run context spec §3.2): display name and org role
229
+ * only (never email or ids). Absent in older logs, on a sub-agent's task or `SendMessage`
230
+ * message. Model-visible only through the sender line, written when the sender changes
231
+ * (`senderLines`, runtime/context/run-context.ts).
232
+ */
233
+ sender: MessageSenderSchema.optional(),
234
+ /**
235
+ * The sender's time zone (IANA) and language at send time (run context spec §3.4): the
236
+ * account setting, else the browser's, else the org defaults. Not model-visible: the next
237
+ * run's `run_context` is derived from them.
238
+ */
239
+ timeZone: z.string().min(1).max(64).optional(),
240
+ locale: z.enum(RUN_CONTEXT_LOCALES).optional(),
196
241
  clientMessageId: z.string().optional(),
197
242
  /**
198
243
  * A retry after a failed run (UI refresh B): the seq of the message it repeats. Display only
@@ -232,13 +277,16 @@ export const ConversationEventSchema = z.discriminatedUnion("type", [
232
277
  */
233
278
  kind: z.enum(["task", "message"]).optional(),
234
279
  /**
235
- * A follow-up (`resume`, final review I1): the frozen tools and org skills intersected
236
- * with the current version (`narrowFollowUp`); the child's run uses these instead of
237
- * the frozen ones. Absent on a first dispatch and in older logs.
280
+ * A follow-up (`resume`, final review I1): the frozen and the current version's
281
+ * turned-off tools together, and the frozen org skills intersected with the current
282
+ * ones (`narrowFollowUp`); the child's run uses these instead of the frozen ones.
283
+ * Absent on a first dispatch and in older logs; logs from before tools were on by
284
+ * default carry an enabled `tools` list instead of `disabledTools` (read as no tool
285
+ * narrowing).
238
286
  */
239
287
  narrowed: z
240
288
  .object({
241
- tools: z.array(AgentToolRef),
289
+ disabledTools: z.array(DisabledToolRef).optional(),
242
290
  skills: z
243
291
  .object({ orgSkills: z.array(z.string()), pinned: z.array(z.string()).optional() })
244
292
  .optional(),
@@ -380,6 +428,13 @@ export const ConversationEventSchema = z.discriminatedUnion("type", [
380
428
  callId: z.string().optional(),
381
429
  })),
382
430
  ev("reminder", z.object({ step: count, text: z.string() })),
431
+ /**
432
+ * Who the agent is and the facts of the day (run context spec §3.1), written at run start
433
+ * (`RunContextService.record`): the conversation's first one holds every field that applies, a
434
+ * later one only the fields that changed. **Model-visible**: rendered at its position as a
435
+ * system message (`runContextText`); a summary covering it restores the current values.
436
+ */
437
+ ev("run_context", RunContextSchema),
383
438
  /**
384
439
  * The step's resolved tool set differs from the one the conversation's previous model request
385
440
  * offered (`toolSetChange`): tool names as the model sees them, sorted. Written before that
@@ -0,0 +1,28 @@
1
+ import type { KernelSchemaDb } from "../db/kernel-schema.js";
2
+ import type { EventPayload } from "./events.js";
3
+ /** The name of an anonymous IM guest whose IM profile gives none. */
4
+ export declare const ANONYMOUS_SENDER_NAME = "Anonymous guest";
5
+ /** What the browser sent with a message (run context spec §3.4); both optional. */
6
+ export interface BrowserContext {
7
+ timeZone?: string | undefined;
8
+ locale?: "zh" | "en" | undefined;
9
+ }
10
+ /** The `user_message` fields {@link readMessageContext} fills. */
11
+ export type MessageContext = Pick<EventPayload<"user_message">, "sender" | "timeZone" | "locale">;
12
+ /**
13
+ * Who wrote a message and in which time zone and language (run context spec §3.2, §3.4), read in
14
+ * the message's transaction (`t`):
15
+ * - `sender`: the account's display name and org role at send time; the org's anonymous guest
16
+ * account (`org_anonymous_accounts`) is `{ name: <senderName, else "Anonymous guest">, role:
17
+ * "guest", anonymous: true }`. Names are sanitised; an empty one leaves `sender` out.
18
+ * - `timeZone`: the account's setting, else the browser's (when valid), else the org default, else
19
+ * UTC. The anonymous guest account has no setting of its own, so it gets the org default.
20
+ * - `locale`: the browser's UI language, else the org's `locale`.
21
+ */
22
+ export declare function readMessageContext(t: KernelSchemaDb, input: {
23
+ orgId: string;
24
+ accountId: string;
25
+ /** An anonymous IM guest's IM profile name. */
26
+ senderName?: string | undefined;
27
+ browser?: BrowserContext | undefined;
28
+ }): Promise<MessageContext>;
@@ -0,0 +1,56 @@
1
+ import { readOrgSettings } from "../orgs/settings.service.js";
2
+ import { sanitizeSenderName } from "../runtime/context/run-context.js";
3
+ import { isTimeZone } from "../time-zone.js";
4
+ /** The name of an anonymous IM guest whose IM profile gives none. */
5
+ export const ANONYMOUS_SENDER_NAME = "Anonymous guest";
6
+ /**
7
+ * Who wrote a message and in which time zone and language (run context spec §3.2, §3.4), read in
8
+ * the message's transaction (`t`):
9
+ * - `sender`: the account's display name and org role at send time; the org's anonymous guest
10
+ * account (`org_anonymous_accounts`) is `{ name: <senderName, else "Anonymous guest">, role:
11
+ * "guest", anonymous: true }`. Names are sanitised; an empty one leaves `sender` out.
12
+ * - `timeZone`: the account's setting, else the browser's (when valid), else the org default, else
13
+ * UTC. The anonymous guest account has no setting of its own, so it gets the org default.
14
+ * - `locale`: the browser's UI language, else the org's `locale`.
15
+ */
16
+ export async function readMessageContext(t, input) {
17
+ const row = await t
18
+ .selectFrom("accounts")
19
+ .leftJoin("memberships", (j) => j
20
+ .onRef("memberships.account_id", "=", "accounts.id")
21
+ .on("memberships.org_id", "=", input.orgId))
22
+ .leftJoin("org_anonymous_accounts as anon", (j) => j.onRef("anon.account_id", "=", "accounts.id").on("anon.org_id", "=", input.orgId))
23
+ .select([
24
+ "accounts.display_name",
25
+ "accounts.time_zone",
26
+ "memberships.role",
27
+ "anon.account_id as anonymous",
28
+ ])
29
+ .where("accounts.id", "=", input.accountId)
30
+ .executeTakeFirst();
31
+ const org = await readOrgSettings(t, input.orgId);
32
+ const anonymous = row?.anonymous !== null && row?.anonymous !== undefined;
33
+ let sender;
34
+ if (row !== undefined) {
35
+ const name = anonymous
36
+ ? sanitizeSenderName(input.senderName ?? "") || ANONYMOUS_SENDER_NAME
37
+ : sanitizeSenderName(row.display_name);
38
+ if (name !== "") {
39
+ sender = anonymous
40
+ ? { name, role: "guest", anonymous: true }
41
+ : { name, ...(row.role !== null && { role: row.role }) };
42
+ }
43
+ }
44
+ const own = row?.time_zone ?? null;
45
+ const browser = input.browser?.timeZone;
46
+ const timeZone = own !== null && isTimeZone(own)
47
+ ? own
48
+ : browser !== undefined && isTimeZone(browser)
49
+ ? browser
50
+ : (org.timeZone ?? "UTC");
51
+ return {
52
+ ...(sender !== undefined && { sender }),
53
+ timeZone,
54
+ locale: input.browser?.locale ?? org.locale,
55
+ };
56
+ }
@@ -5,6 +5,7 @@ import { type InvocationRecord, type RenderedInvocation } from "../skills/invoke
5
5
  import type { AttachmentRef } from "./conversations.service.js";
6
6
  import { type AppendEvent, type EventLog } from "./event-log.js";
7
7
  import type { ConversationEvent, LogContentBlock } from "./events.js";
8
+ import { type MessageContext } from "./message-context.js";
8
9
  /**
9
10
  * Queued messages (UI refresh B, spec §5.7): messages a person queued while a run was going. They
10
11
  * are conversation state in PG, not events: the model has not seen them, so they enter the log only
@@ -113,7 +114,7 @@ export declare function storedSkill(invokedAs: string, invoked: RenderedInvocati
113
114
  first: LogContentBlock;
114
115
  };
115
116
  /** The `user_message` a queued item becomes, as `postUserMessage` would have written it. */
116
- export declare function queuedUserMessage(r: QueueRow): AppendEvent;
117
+ export declare function queuedUserMessage(r: QueueRow, context?: MessageContext): AppendEvent;
117
118
  /**
118
119
  * Appends a queued item inside `t` (the caller holds the conversation row lock): its pick, re-planned
119
120
  * against the selection in effect now, becomes a `model_switched` before the `user_message`, as a
@@ -4,6 +4,7 @@ import { ApiError } from "../errors.js";
4
4
  import { recordedSkillBlocked, } from "../skills/invoke.js";
5
5
  import { payloadJson } from "./event-log.js";
6
6
  import { userMessageIdemKey } from "./idem-keys.js";
7
+ import { readMessageContext } from "./message-context.js";
7
8
  import { planSelection, readSelection } from "./selection.js";
8
9
  /**
9
10
  * Queued messages (UI refresh B, spec §5.7): messages a person queued while a run was going. They
@@ -77,7 +78,7 @@ export function storedSkill(invokedAs, invoked) {
77
78
  return { skill: payloadJson(skill), first: { type: "text", text: invoked.text } };
78
79
  }
79
80
  /** The `user_message` a queued item becomes, as `postUserMessage` would have written it. */
80
- export function queuedUserMessage(r) {
81
+ export function queuedUserMessage(r, context = {}) {
81
82
  const attachments = r.attachments;
82
83
  const skill = r.skill;
83
84
  return {
@@ -91,6 +92,7 @@ export function queuedUserMessage(r) {
91
92
  ],
92
93
  ...(attachments.length > 0 && { attachments }),
93
94
  authorAccountId: r.account_id,
95
+ ...context,
94
96
  clientMessageId: r.client_message_id,
95
97
  ...(skill !== null && { skill: skill.record }),
96
98
  },
@@ -120,7 +122,14 @@ export async function appendQueuedIn(t, eventLog, conversationId, r) {
120
122
  payload: { ...next, byAccountId: r.account_id, reason: "user" },
121
123
  });
122
124
  }
123
- events.push(queuedUserMessage(r));
125
+ // run context spec §3.4: no browser values were stored with a leftover row
126
+ const org = await t
127
+ .selectFrom("conversations")
128
+ .select("org_id")
129
+ .where("id", "=", conversationId)
130
+ .executeTakeFirstOrThrow();
131
+ const context = await readMessageContext(t, { orgId: org.org_id, accountId: r.account_id });
132
+ events.push(queuedUserMessage(r, context));
124
133
  const written = await eventLog.appendIn(conversationId, events);
125
134
  if (next !== null) {
126
135
  await t
@@ -4,6 +4,8 @@ import { Kysely } from "kysely";
4
4
  import { type RegisteredHook } from "../extensions/hooks.js";
5
5
  import { RegistrationLedger } from "../extensions/ledger.js";
6
6
  import type { LockService } from "../infra/lock/lock.service.js";
7
+ import type { ModelEmbeddings } from "../models/embeddings.js";
8
+ import type { HookRunner } from "../runtime/hook-calls.js";
7
9
  import type { EmbedTokens } from "../ui/embed-token.js";
8
10
  import { type UiActionHandler, type UiRender } from "../ui/registry.js";
9
11
  import { type BusSubscriber } from "./bus.js";
@@ -22,6 +24,17 @@ export interface KernelDeps {
22
24
  keyring: Keyring;
23
25
  /** Verifies embed tokens (`ctx.ui` embed requests; the one `EmbedTokens` provider). */
24
26
  embedTokens: Pick<EmbedTokens, "verify">;
27
+ /**
28
+ * The `ctx.models` broker (the one `ModelEmbeddings` provider). Absent (a ctx built alone in a
29
+ * test): `ctx.models` calls reject.
30
+ */
31
+ models?: Pick<ModelEmbeddings, "embed" | "describe">;
32
+ /**
33
+ * The host's hook registry: `ctx.models.embed` fires `model.request` through it (spec B §5.4).
34
+ * A required key, so no builder leaves policy hooks out by omission (fail closed by
35
+ * construction); only a ctx built alone in a test passes `undefined` (no hooks fire).
36
+ */
37
+ hooks: HookRunner | undefined;
25
38
  runWorkers: boolean;
26
39
  /** 内核 logger(`debug` 可选:插件 Logger 没有它,测试可不给)。 */
27
40
  log: Logger & {
@@ -102,7 +115,8 @@ export declare class LiveConfig {
102
115
  * `deploymentConfig` may be a {@link LiveConfig} (shared by the instance, replaceable in place);
103
116
  * otherwise a fixed value is wrapped.
104
117
  * - Granted automatically: `kv`, `lock`, `bus`, `queue`, `log`, `db`, `config`, `provide`;
105
- * - `secrets` only with `permissions.secrets`, `storage` only with `permissions.storage`; `http.route`
118
+ * - `secrets` only with `permissions.secrets`, `storage` only with `permissions.storage`, `models`
119
+ * only with `permissions.models` (and only its `embedding` purposes, through `deps.models`); `http.route`
106
120
  * only the method + path declared in `permissions.http`; `tools.register` only names declared in
107
121
  * `permissions.tools`; `ui.view` / `ui.action` only ids declared in `permissions.ui.views` (during
108
122
  * setup only); `ui.invalidate` sends a refresh over the kernel bus (namespace `kernel`), across
@@ -164,7 +164,8 @@ export class LiveConfig {
164
164
  * `deploymentConfig` may be a {@link LiveConfig} (shared by the instance, replaceable in place);
165
165
  * otherwise a fixed value is wrapped.
166
166
  * - Granted automatically: `kv`, `lock`, `bus`, `queue`, `log`, `db`, `config`, `provide`;
167
- * - `secrets` only with `permissions.secrets`, `storage` only with `permissions.storage`; `http.route`
167
+ * - `secrets` only with `permissions.secrets`, `storage` only with `permissions.storage`, `models`
168
+ * only with `permissions.models` (and only its `embedding` purposes, through `deps.models`); `http.route`
168
169
  * only the method + path declared in `permissions.http`; `tools.register` only names declared in
169
170
  * `permissions.tools`; `ui.view` / `ui.action` only ids declared in `permissions.ui.views` (during
170
171
  * setup only); `ui.invalidate` sends a refresh over the kernel bus (namespace `kernel`), across
@@ -218,6 +219,24 @@ export function createExtensionContext(deps, manifest, deploymentConfig, extensi
218
219
  plugins: async () => [name],
219
220
  }).forPlugin(name)
220
221
  : undefined;
222
+ // ctx.models: only with permissions.models; the broker accepts only the purposes declared there
223
+ // with kind embedding (spec B §5.4), aborted by this instance's signal
224
+ // a frozen copy: the approved manifest, not an object the extension could change later
225
+ const declaredModels = Object.freeze(structuredClone(perms.models ?? []).map((m) => Object.freeze(m)));
226
+ const modelsApi = declaredModels.length > 0
227
+ ? {
228
+ embed: async (req) => {
229
+ if (!deps.models)
230
+ throw new Error(`plugin ${name}: ctx.models is not available`);
231
+ return deps.models.embed(name, declaredModels, req, lifecycle.signal, deps.hooks);
232
+ },
233
+ describe: async (req) => {
234
+ if (!deps.models)
235
+ throw new Error(`plugin ${name}: ctx.models is not available`);
236
+ return deps.models.describe(name, declaredModels, req);
237
+ },
238
+ }
239
+ : undefined;
221
240
  const declaredRoutes = new Set((perms.http ?? []).map((r) => `${r.method} ${r.path}`));
222
241
  const declaredTools = new Set(perms.tools ?? []);
223
242
  const declaredHooks = new Set(perms.hooks ?? []);
@@ -561,7 +580,8 @@ export function createExtensionContext(deps, manifest, deploymentConfig, extensi
561
580
  return closing;
562
581
  },
563
582
  };
564
- // 声明了 secrets / storage 时是普通属性;未声明时是不可枚举的抛错 getter——展开 / 打印 ctx 不会触发越权与审计
583
+ // secrets / storage / models: a plain property when declared; otherwise a non-enumerable getter
584
+ // that throws, so spreading or printing ctx triggers no denial and no audit
565
585
  const gated = (key, api) => {
566
586
  if (api) {
567
587
  Object.assign(ctx, { [key]: api });
@@ -575,6 +595,7 @@ export function createExtensionContext(deps, manifest, deploymentConfig, extensi
575
595
  };
576
596
  gated("secrets", secretsApi);
577
597
  gated("storage", storageApi);
598
+ gated("models", modelsApi);
578
599
  return ctx;
579
600
  }
580
601
  /**