@capybara-hq/kernel 0.1.0-rc.23 → 0.1.0-rc.25

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 (293) hide show
  1. package/bootstrap.json +25 -25
  2. package/dist/admin/admin.module.d.ts +2 -1
  3. package/dist/admin/admin.module.js +9 -3
  4. package/dist/admin/health.service.d.ts +2 -2
  5. package/dist/admin/health.service.js +6 -2
  6. package/dist/admin/outbox-dead.controller.d.ts +23 -0
  7. package/dist/admin/outbox-dead.controller.js +62 -0
  8. package/dist/admin/outbox-dead.schemas.d.ts +8 -0
  9. package/dist/admin/outbox-dead.schemas.js +18 -0
  10. package/dist/admin/outbox-dead.service.d.ts +66 -0
  11. package/dist/admin/outbox-dead.service.js +179 -0
  12. package/dist/admin/overview.service.d.ts +40 -5
  13. package/dist/admin/overview.service.js +41 -7
  14. package/dist/agents/agents.module.js +3 -0
  15. package/dist/agents/agents.service.d.ts +6 -1
  16. package/dist/agents/agents.service.js +11 -2
  17. package/dist/agents/from-template.js +1 -1
  18. package/dist/background/finish.d.ts +5 -2
  19. package/dist/background/finish.js +14 -3
  20. package/dist/background/launch.d.ts +2 -1
  21. package/dist/background/launch.js +5 -2
  22. package/dist/background/store.d.ts +8 -0
  23. package/dist/background/store.js +24 -0
  24. package/dist/catalog/admin-catalog.controller.d.ts +21 -2
  25. package/dist/catalog/admin-catalog.controller.js +45 -6
  26. package/dist/catalog/admin-catalog.schemas.d.ts +5 -0
  27. package/dist/catalog/admin-catalog.schemas.js +8 -0
  28. package/dist/catalog/catalog-import.module.js +0 -4
  29. package/dist/catalog/catalog-scope.service.d.ts +63 -26
  30. package/dist/catalog/catalog-scope.service.js +146 -71
  31. package/dist/catalog/catalog.module.d.ts +2 -1
  32. package/dist/catalog/catalog.module.js +9 -4
  33. package/dist/catalog/catalog.service.d.ts +11 -4
  34. package/dist/catalog/catalog.service.js +21 -5
  35. package/dist/catalog/cli.d.ts +4 -3
  36. package/dist/catalog/cli.js +8 -13
  37. package/dist/catalog/job-ids.d.ts +8 -20
  38. package/dist/catalog/job-ids.js +11 -16
  39. package/dist/catalog/marketplaces.service.d.ts +1 -1
  40. package/dist/catalog/org-plugin-uploads.d.ts +11 -4
  41. package/dist/catalog/org-plugin-uploads.js +21 -6
  42. package/dist/catalog/owned-items.d.ts +6 -13
  43. package/dist/catalog/owned-items.js +11 -29
  44. package/dist/catalog/owned-plugin-cleanup.d.ts +8 -17
  45. package/dist/catalog/owned-plugin-cleanup.js +12 -66
  46. package/dist/catalog/platform-components.d.ts +56 -34
  47. package/dist/catalog/platform-components.js +68 -78
  48. package/dist/catalog/platform-import-update.d.ts +50 -0
  49. package/dist/catalog/platform-import-update.js +116 -0
  50. package/dist/catalog/plugin-import.d.ts +64 -26
  51. package/dist/catalog/plugin-import.js +113 -77
  52. package/dist/catalog/plugin-upgrade.d.ts +22 -4
  53. package/dist/catalog/plugin-upgrade.js +26 -19
  54. package/dist/catalog/scope-jobs.d.ts +59 -0
  55. package/dist/catalog/scope-jobs.js +65 -0
  56. package/dist/catalog/scope-sync-workers.d.ts +22 -0
  57. package/dist/catalog/scope-sync-workers.js +58 -2
  58. package/dist/catalog/scope-sync.d.ts +40 -65
  59. package/dist/catalog/scope-sync.js +114 -122
  60. package/dist/channels/channels.module.d.ts +5 -2
  61. package/dist/channels/channels.module.js +9 -2
  62. package/dist/channels/deliver-job.d.ts +25 -0
  63. package/dist/channels/deliver-job.js +25 -0
  64. package/dist/channels/inbound.d.ts +1 -1
  65. package/dist/channels/inbound.js +4 -17
  66. package/dist/channels/jobs.d.ts +28 -18
  67. package/dist/channels/jobs.js +63 -26
  68. package/dist/channels/threads.d.ts +4 -3
  69. package/dist/channels/threads.js +4 -3
  70. package/dist/config/schema.d.ts +0 -3
  71. package/dist/config/schema.js +11 -20
  72. package/dist/conversations/agent-tree.d.ts +16 -0
  73. package/dist/conversations/agent-tree.js +36 -0
  74. package/dist/conversations/conversations.controller.js +4 -2
  75. package/dist/conversations/conversations.service.d.ts +61 -19
  76. package/dist/conversations/conversations.service.js +69 -43
  77. package/dist/conversations/event-log.d.ts +7 -10
  78. package/dist/conversations/event-log.js +24 -15
  79. package/dist/conversations/events.d.ts +21 -0
  80. package/dist/conversations/events.js +26 -2
  81. package/dist/conversations/queue.service.d.ts +8 -3
  82. package/dist/conversations/queue.service.js +37 -13
  83. package/dist/conversations/source.d.ts +10 -0
  84. package/dist/conversations/source.js +17 -0
  85. package/dist/conversations/titles.d.ts +21 -8
  86. package/dist/conversations/titles.js +42 -15
  87. package/dist/conversations/tree.d.ts +10 -0
  88. package/dist/conversations/tree.js +35 -0
  89. package/dist/db/kernel-schema.d.ts +35 -22
  90. package/dist/devices/devices.service.d.ts +23 -11
  91. package/dist/devices/devices.service.js +34 -26
  92. package/dist/errors.d.ts +11 -0
  93. package/dist/errors.js +11 -0
  94. package/dist/evals/run-replay.d.ts +13 -2
  95. package/dist/evals/run-replay.js +42 -9
  96. package/dist/evals/snapshot.d.ts +7 -1
  97. package/dist/evals/snapshot.js +2 -1
  98. package/dist/extensions/extensions.module.js +3 -0
  99. package/dist/extensions/hooks.d.ts +22 -3
  100. package/dist/extensions/hooks.js +15 -1
  101. package/dist/extensions/lifecycle-hooks.d.ts +99 -0
  102. package/dist/extensions/lifecycle-hooks.js +273 -0
  103. package/dist/extensions/lifecycle.d.ts +6 -1
  104. package/dist/extensions/lifecycle.js +9 -2
  105. package/dist/extensions/org-config.d.ts +13 -1
  106. package/dist/extensions/org-config.js +19 -2
  107. package/dist/extensions/permission-view.d.ts +9 -5
  108. package/dist/extensions/permission-view.js +9 -4
  109. package/dist/extensions/point-defaults.d.ts +28 -1
  110. package/dist/extensions/point-defaults.js +44 -13
  111. package/dist/extensions/usage-subscribers.d.ts +43 -0
  112. package/dist/extensions/usage-subscribers.js +108 -0
  113. package/dist/http/api.module.js +2 -0
  114. package/dist/inbox/inbox.service.d.ts +6 -20
  115. package/dist/inbox/inbox.service.js +0 -3
  116. package/dist/inbox/org-notices.d.ts +1 -1
  117. package/dist/inbox/platform-inbox.service.d.ts +3 -32
  118. package/dist/inbox/platform-inbox.service.js +5 -54
  119. package/dist/index.d.ts +1 -0
  120. package/dist/index.js +1 -0
  121. package/dist/infra/cli/kernel-cli.module.js +5 -0
  122. package/dist/infra/events/kernel-events.d.ts +9 -35
  123. package/dist/infra/outbox/outbox-relay.module.d.ts +6 -0
  124. package/dist/infra/outbox/outbox-relay.module.js +18 -0
  125. package/dist/infra/outbox/outbox.dispatcher.d.ts +103 -0
  126. package/dist/infra/outbox/outbox.dispatcher.js +310 -0
  127. package/dist/infra/outbox/outbox.module.d.ts +24 -0
  128. package/dist/infra/outbox/outbox.module.js +50 -0
  129. package/dist/infra/outbox/outbox.relay.d.ts +31 -0
  130. package/dist/infra/outbox/outbox.relay.js +76 -0
  131. package/dist/infra/outbox/outbox.service.d.ts +51 -0
  132. package/dist/infra/outbox/outbox.service.js +131 -0
  133. package/dist/infra/outbox/registry.d.ts +244 -0
  134. package/dist/infra/outbox/registry.js +234 -0
  135. package/dist/infra/queue/queue-names.d.ts +8 -0
  136. package/dist/infra/queue/queue-names.js +17 -0
  137. package/dist/kernel.module.js +3 -0
  138. package/dist/local-devices/device-policy.service.d.ts +4 -0
  139. package/dist/local-devices/device-policy.service.js +61 -3
  140. package/dist/local-devices/machines.d.ts +13 -5
  141. package/dist/local-devices/machines.js +45 -7
  142. package/dist/local-devices/policy-summary.d.ts +44 -1
  143. package/dist/local-devices/policy-summary.js +69 -0
  144. package/dist/models/embeddings.d.ts +9 -9
  145. package/dist/models/embeddings.js +11 -18
  146. package/dist/models/models.module.js +3 -0
  147. package/dist/orgs/directory-sync.js +1 -1
  148. package/dist/orgs/members.service.js +1 -1
  149. package/dist/orgs/offboarding.d.ts +50 -57
  150. package/dist/orgs/offboarding.js +117 -162
  151. package/dist/orgs/orgs.module.js +3 -0
  152. package/dist/orgs/orgs.service.d.ts +11 -5
  153. package/dist/orgs/orgs.service.js +22 -6
  154. package/dist/overrides.d.ts +23 -3
  155. package/dist/overrides.js +12 -2
  156. package/dist/platform/exclusions.js +5 -0
  157. package/dist/platform/ops/admin.ops.js +18 -2
  158. package/dist/platform/ops/catalog-admin.ops.d.ts +3 -1
  159. package/dist/platform/ops/catalog-admin.ops.js +32 -4
  160. package/dist/platform/ops/inbox.ops.js +4 -20
  161. package/dist/platform/ops/outbox.ops.d.ts +21 -0
  162. package/dist/platform/ops/outbox.ops.js +125 -0
  163. package/dist/platform/ops/platform.ops.d.ts +1 -0
  164. package/dist/platform/ops/platform.ops.js +6 -3
  165. package/dist/platform/ops/schedules.ops.js +40 -1
  166. package/dist/platform/platform-ops.module.d.ts +2 -1
  167. package/dist/platform/platform-ops.module.js +3 -0
  168. package/dist/platform/route-schemas.js +3 -0
  169. package/dist/roles/worker-role.d.ts +10 -5
  170. package/dist/roles/worker-role.js +19 -9
  171. package/dist/roles/worker.module.js +11 -8
  172. package/dist/runtime/context/build.d.ts +3 -0
  173. package/dist/runtime/context/build.js +15 -0
  174. package/dist/runtime/context/plugin-context.d.ts +20 -0
  175. package/dist/runtime/context/plugin-context.js +30 -0
  176. package/dist/runtime/langgraph-loop.js +17 -5
  177. package/dist/runtime/limits.d.ts +15 -0
  178. package/dist/runtime/limits.js +25 -0
  179. package/dist/runtime/loop.d.ts +16 -3
  180. package/dist/runtime/loop.js +2 -1
  181. package/dist/runtime/maintenance.d.ts +7 -3
  182. package/dist/runtime/maintenance.js +52 -12
  183. package/dist/runtime/model-call.d.ts +20 -17
  184. package/dist/runtime/model-call.js +15 -24
  185. package/dist/runtime/plugin-context.service.d.ts +69 -0
  186. package/dist/runtime/plugin-context.service.js +208 -0
  187. package/dist/runtime/queue-lost-jobs.d.ts +24 -0
  188. package/dist/runtime/queue-lost-jobs.js +51 -0
  189. package/dist/runtime/run-control.d.ts +47 -5
  190. package/dist/runtime/run-control.js +79 -12
  191. package/dist/runtime/run-finish.d.ts +39 -12
  192. package/dist/runtime/run-finish.js +97 -14
  193. package/dist/runtime/run-jobs.d.ts +95 -13
  194. package/dist/runtime/run-jobs.js +199 -28
  195. package/dist/runtime/run-orphan-check.job.d.ts +142 -0
  196. package/dist/runtime/run-orphan-check.job.js +339 -0
  197. package/dist/runtime/run-processors.d.ts +16 -9
  198. package/dist/runtime/run-processors.js +1 -1
  199. package/dist/runtime/run-queue.d.ts +75 -53
  200. package/dist/runtime/run-queue.js +189 -263
  201. package/dist/runtime/run-steps.d.ts +1 -2
  202. package/dist/runtime/run-steps.js +8 -11
  203. package/dist/runtime/run-worker.d.ts +26 -16
  204. package/dist/runtime/run-worker.js +132 -37
  205. package/dist/runtime/runtime.module.d.ts +2 -3
  206. package/dist/runtime/runtime.module.js +7 -6
  207. package/dist/runtime/step-log.d.ts +16 -4
  208. package/dist/runtime/step-log.js +26 -6
  209. package/dist/runtime/stream.controller.d.ts +2 -4
  210. package/dist/runtime/stream.controller.js +5 -11
  211. package/dist/runtime/subagents/child.js +1 -1
  212. package/dist/runtime/subagents/definition.d.ts +2 -1
  213. package/dist/runtime/subagents/definition.js +4 -2
  214. package/dist/runtime/subagents/deliveries.d.ts +6 -3
  215. package/dist/runtime/subagents/deliveries.js +16 -7
  216. package/dist/runtime/subagents/dispatch.d.ts +12 -12
  217. package/dist/runtime/subagents/dispatch.js +14 -38
  218. package/dist/runtime/subagents/messages.d.ts +5 -1
  219. package/dist/runtime/subagents/messages.js +11 -3
  220. package/dist/runtime/subagents/skill-fork.d.ts +3 -3
  221. package/dist/runtime/subagents/skill-fork.js +8 -5
  222. package/dist/runtime/subagents/subagents.service.js +1 -1
  223. package/dist/runtime/subagents/tree-jobs.d.ts +61 -0
  224. package/dist/runtime/subagents/tree-jobs.js +86 -0
  225. package/dist/runtime/usage-report-jobs.d.ts +23 -48
  226. package/dist/runtime/usage-report-jobs.js +67 -119
  227. package/dist/runtime/usage-report.d.ts +28 -77
  228. package/dist/runtime/usage-report.js +35 -213
  229. package/dist/runtime/waits.d.ts +48 -198
  230. package/dist/runtime/waits.js +103 -805
  231. package/dist/sandbox/jobs.d.ts +20 -10
  232. package/dist/sandbox/jobs.js +23 -17
  233. package/dist/sandbox/sandbox.service.d.ts +17 -4
  234. package/dist/sandbox/sandbox.service.js +55 -14
  235. package/dist/schedules/calendar.d.ts +134 -0
  236. package/dist/schedules/calendar.js +410 -0
  237. package/dist/schedules/fire.d.ts +26 -7
  238. package/dist/schedules/fire.js +91 -22
  239. package/dist/schedules/job-ids.d.ts +66 -17
  240. package/dist/schedules/job-ids.js +81 -13
  241. package/dist/schedules/run-tracker.d.ts +0 -5
  242. package/dist/schedules/run-tracker.js +2 -14
  243. package/dist/schedules/scan.job.d.ts +13 -32
  244. package/dist/schedules/scan.job.js +50 -164
  245. package/dist/schedules/schedule-math.d.ts +42 -0
  246. package/dist/schedules/schedule-math.js +52 -0
  247. package/dist/schedules/scheduled-tasks.service.d.ts +22 -6
  248. package/dist/schedules/scheduled-tasks.service.js +70 -14
  249. package/dist/schedules/schedules.controller.d.ts +5 -1
  250. package/dist/schedules/schedules.controller.js +15 -1
  251. package/dist/schedules/schedules.module.js +0 -4
  252. package/dist/schedules/schedules.schemas.d.ts +35 -0
  253. package/dist/schedules/schedules.schemas.js +27 -0
  254. package/dist/schedules/store.d.ts +5 -0
  255. package/dist/schedules/store.js +20 -0
  256. package/dist/skills/changes.controller.d.ts +1 -1
  257. package/dist/skills/changes.controller.js +1 -1
  258. package/dist/tools/approvals.service.d.ts +41 -11
  259. package/dist/tools/approvals.service.js +108 -14
  260. package/dist/tools/builtin-names.d.ts +5 -3
  261. package/dist/tools/builtin-names.js +12 -4
  262. package/dist/tools/builtins/builtin-tools.d.ts +1 -2
  263. package/dist/tools/builtins/builtin-tools.js +21 -17
  264. package/dist/tools/builtins/sandbox/bash.js +9 -3
  265. package/dist/tools/builtins/sandbox/common.d.ts +18 -1
  266. package/dist/tools/builtins/sandbox/common.js +14 -1
  267. package/dist/tools/builtins/sandbox/index.d.ts +2 -1
  268. package/dist/tools/builtins/sandbox/index.js +4 -1
  269. package/dist/tools/builtins/sandbox/task-list.d.ts +12 -0
  270. package/dist/tools/builtins/sandbox/task-list.js +130 -0
  271. package/dist/tools/builtins/sandbox/task-output.d.ts +8 -1
  272. package/dist/tools/builtins/sandbox/task-output.js +21 -3
  273. package/dist/tools/builtins/web/extract.d.ts +2 -4
  274. package/dist/tools/builtins/web/extract.js +2 -5
  275. package/dist/tools/pipeline.d.ts +12 -3
  276. package/dist/tools/pipeline.js +6 -1
  277. package/dist/tools/questions.service.d.ts +30 -10
  278. package/dist/tools/questions.service.js +41 -27
  279. package/dist/tools/registry.d.ts +12 -3
  280. package/dist/tools/registry.js +13 -3
  281. package/dist/tools/tools.module.js +4 -3
  282. package/package.json +3 -3
  283. package/src/migrations/0118_device_policy_ops.sql +6 -0
  284. package/src/migrations/0119_outbox.sql +22 -0
  285. package/src/migrations/0120_drop_usage_report_sweep.sql +7 -0
  286. package/src/migrations/0121_drop_platform_migration_runs.sql +12 -0
  287. package/src/migrations/0122_drop_scheduled_task_runs_rechecked_at.sql +5 -0
  288. package/src/migrations/0123_pgvector.sql +27 -0
  289. package/src/migrations/0124_conversation_source.sql +36 -0
  290. package/dist/catalog/platform-migration.d.ts +0 -115
  291. package/dist/catalog/platform-migration.js +0 -583
  292. package/dist/infra/queue/add-job-once.d.ts +0 -14
  293. package/dist/infra/queue/add-job-once.js +0 -16
@@ -10,6 +10,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
10
10
  import { Inject, Injectable } from "@nestjs/common";
11
11
  import { z } from "zod";
12
12
  import { AgentsService } from "../../agents/agents.service.js";
13
+ import { conversationSourceOf } from "../../conversations/source.js";
13
14
  import { AccountsService } from "../../identity/accounts.js";
14
15
  import { PreferencesSchema } from "../../identity/me.schemas.js";
15
16
  import { KernelDb } from "../../infra/database/kernel-db.js";
@@ -81,12 +82,14 @@ let PlatformOperationsProvider = class PlatformOperationsProvider {
81
82
  * default-on spec §8): every tool the org offers that the definition does not turn off, builtins
82
83
  * by name, extension tools as `plugin__<plugin>__<tool>`, connector tools as
83
84
  * `mcp__<slug>__<tool>`; the ones that cannot load now are listed with the registry's reason.
85
+ * Listed for the source of the conversation the operation runs in (memory plugin spec §6.2).
84
86
  */
85
- async toolKeys(orgId, d) {
86
- const resolved = await this.tools.forAgent(orgId, {
87
+ async toolKeys(ctx, d) {
88
+ const resolved = await this.tools.forAgent(ctx.orgId, {
87
89
  disabledTools: d.disabledTools ?? [],
88
90
  subagentTools: d.subagentTools,
89
91
  subagents: d.subagents,
92
+ source: await conversationSourceOf(this.db.db, ctx.conversationId),
90
93
  });
91
94
  return {
92
95
  keys: [...new Set(resolved.tools.map((t) => t.key))],
@@ -142,7 +145,7 @@ let PlatformOperationsProvider = class PlatformOperationsProvider {
142
145
  const agent = await this.agents.get(ctx.orgId, ctx.agentId, ctx.actorAccountId);
143
146
  const d = agent.definition;
144
147
  const [{ keys: toolKeys, unavailable }, skills] = await Promise.all([
145
- this.toolKeys(ctx.orgId, d),
148
+ this.toolKeys(ctx, d),
146
149
  this.skillNames(ctx, d),
147
150
  ]);
148
151
  const sandbox = toolKeys.some((k) => SANDBOX_TOOL_NAMES.includes(k));
@@ -10,7 +10,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
10
10
  import { Inject, Injectable } from "@nestjs/common";
11
11
  import { z } from "zod";
12
12
  import { ScheduledTasksService, } from "../../schedules/scheduled-tasks.service.js";
13
- import { createInputOf, grantsOf, ScheduleChatTargetsQuery, ScheduleCreateBody, ScheduleGrantableQuery, ScheduleGrantParams, ScheduleGrantsBody, ScheduleListQuery, ScheduleParams, ScheduleRunBody, ScheduleRunsQuery, ScheduleUpdateBody, updateInputOf, } from "../../schedules/schedules.schemas.js";
13
+ import { calendarInputOf, createInputOf, grantsOf, ScheduleCalendarQuery, ScheduleChatTargetsQuery, ScheduleCreateBody, ScheduleGrantableQuery, ScheduleGrantParams, ScheduleGrantsBody, ScheduleListQuery, ScheduleParams, ScheduleRunBody, ScheduleRunsQuery, ScheduleUpdateBody, updateInputOf, } from "../../schedules/schedules.schemas.js";
14
14
  import { defineOperation } from "../operation.js";
15
15
  import { PlatformOperations } from "../registry.js";
16
16
  import { named, orElse } from "./summary.js";
@@ -98,6 +98,45 @@ let SchedulesOperations = class SchedulesOperations {
98
98
  return { items: items.map(row) };
99
99
  },
100
100
  }),
101
+ defineOperation({
102
+ id: "schedules.calendar",
103
+ description: "Your scheduled task runs and planned occurrences between two instants (at most 43 days): recorded runs with their status, planned runs computed from each active task's schedule up to 42 days ahead, and dense tasks summarized per day. Org admins see every task with all=true. from and to are ISO instants with an offset; timeZone (IANA) sets the local days used to summarize dense tasks; taskId lists one task's items, never summarized (then at most 2 days). truncated means a limit cut the range at horizon.",
104
+ input: ScheduleCalendarQuery,
105
+ example: {
106
+ from: "2026-11-09T00:00:00+08:00",
107
+ to: "2026-11-16T00:00:00+08:00",
108
+ timeZone: "Asia/Shanghai",
109
+ },
110
+ authz: { orgAction: "org.read" },
111
+ mirrors: ["GET /api/v1/orgs/:orgId/schedules/calendar"],
112
+ confirm: "read",
113
+ errors: [
114
+ {
115
+ code: "validation_failed",
116
+ next: "Narrow the range to 43 days or less (2 days with taskId), with from before to.",
117
+ },
118
+ {
119
+ code: "forbidden",
120
+ next: "Reading every task needs the org admin role: call without all, or ask an org admin.",
121
+ },
122
+ {
123
+ code: "schedule.not_found",
124
+ next: "Check taskId with schedules.list: members see only their own tasks; an org admin finds another member's task id with schedules.list all=true, then reads it here by taskId (all is not needed).",
125
+ },
126
+ ],
127
+ run: async (input, ctx) => {
128
+ const answer = await this.tasks.calendar(ctx.orgId, this.actor(ctx), calendarInputOf(input));
129
+ return {
130
+ ...answer,
131
+ tasks: answer.tasks.map((t) => ({
132
+ id: t.id,
133
+ name: t.name,
134
+ agentId: t.agentId,
135
+ status: t.status,
136
+ })),
137
+ };
138
+ },
139
+ }),
101
140
  defineOperation({
102
141
  id: "schedules.chat-targets",
103
142
  description: "The IM chats you can point a chat-mode scheduled task at: your direct chats with each active channel connection's bot (one you have messaged before), and the groups you have talked in when the channel has threads. Each gives { connectionId, chatId, chatType } for schedules.create, and the connection's agentId, which the task must use.",
@@ -21,6 +21,7 @@ import { ModelsOperations } from "./ops/models.ops.js";
21
21
  import { OrgPluginsOperations } from "./ops/org-plugins.ops.js";
22
22
  import { OrgSettingsOperations } from "./ops/org-settings.ops.js";
23
23
  import { OrgsOperations } from "./ops/orgs.ops.js";
24
+ import { OutboxOperations } from "./ops/outbox.ops.js";
24
25
  import { PlatformOperationsProvider } from "./ops/platform.ops.js";
25
26
  import { PluginsOperations } from "./ops/plugins.ops.js";
26
27
  import { PreviewersOperations } from "./ops/previewers.ops.js";
@@ -34,7 +35,7 @@ import { UiOperations } from "./ops/ui.ops.js";
34
35
  * One provider per domain, each taking `PlatformOperations` as its first constructor argument:
35
36
  * the parity test in `tools/checks` builds the operations from it without a Nest app.
36
37
  */
37
- export declare const PLATFORM_OPERATION_PROVIDERS: readonly [typeof PlatformOperationsProvider, typeof SkillsOperations, typeof AgentsOperations, typeof AgentTemplatesOperations, typeof PluginsOperations, typeof MarketplacesOperations, typeof RequestsOperations, typeof ConnectorsOperations, typeof ExtensionsOperations, typeof ConversationsOperations, typeof ComponentsOperations, typeof AccountsOperations, typeof OrgsOperations, typeof AdminOperations, typeof CatalogAdminOperations, typeof OrgPluginsOperations, typeof ExtensionsAdminOperations, typeof ModelsOperations, typeof InboxOperations, typeof ApprovalsOperations, typeof ChannelsOperations, typeof OrgSettingsOperations, typeof EvalsOperations, typeof BackgroundOperations, typeof PreviewersOperations, typeof DevicesOperations, typeof AgentSkillsOperations, typeof ThemesOperations, typeof SetupOperations, typeof UiOperations, typeof AdminItemsOperations, typeof SchedulesOperations];
38
+ export declare const PLATFORM_OPERATION_PROVIDERS: readonly [typeof PlatformOperationsProvider, typeof SkillsOperations, typeof AgentsOperations, typeof AgentTemplatesOperations, typeof PluginsOperations, typeof MarketplacesOperations, typeof RequestsOperations, typeof ConnectorsOperations, typeof ExtensionsOperations, typeof ConversationsOperations, typeof ComponentsOperations, typeof AccountsOperations, typeof OrgsOperations, typeof AdminOperations, typeof CatalogAdminOperations, typeof OrgPluginsOperations, typeof ExtensionsAdminOperations, typeof ModelsOperations, typeof InboxOperations, typeof ApprovalsOperations, typeof ChannelsOperations, typeof OrgSettingsOperations, typeof EvalsOperations, typeof BackgroundOperations, typeof PreviewersOperations, typeof DevicesOperations, typeof AgentSkillsOperations, typeof ThemesOperations, typeof SetupOperations, typeof UiOperations, typeof AdminItemsOperations, typeof SchedulesOperations, typeof OutboxOperations];
38
39
  /**
39
40
  * The `Platform` tool's operations (ruling P2): one provider per domain, each registering its
40
41
  * operations into `PlatformOperations` from `onModuleInit`. It imports the domain modules, which
@@ -49,6 +49,7 @@ import { ModelsOperations } from "./ops/models.ops.js";
49
49
  import { OrgPluginsOperations } from "./ops/org-plugins.ops.js";
50
50
  import { OrgSettingsOperations } from "./ops/org-settings.ops.js";
51
51
  import { OrgsOperations } from "./ops/orgs.ops.js";
52
+ import { OutboxOperations } from "./ops/outbox.ops.js";
52
53
  import { PlatformOperationsProvider } from "./ops/platform.ops.js";
53
54
  import { PluginsOperations } from "./ops/plugins.ops.js";
54
55
  import { PreviewersOperations } from "./ops/previewers.ops.js";
@@ -107,6 +108,8 @@ export const PLATFORM_OPERATION_PROVIDERS = [
107
108
  AdminItemsOperations,
108
109
  // scheduled tasks (scheduled tasks spec §10)
109
110
  SchedulesOperations,
111
+ // dead outbox rows (transactional outbox spec §3.4)
112
+ OutboxOperations,
110
113
  ];
111
114
  /**
112
115
  * The `Platform` tool's operations (ruling P2): one provider per domain, each registering its
@@ -2,6 +2,7 @@ import { ADMIN_ROUTES } from "../admin/admin.schemas.js";
2
2
  import { ADMIN_ITEM_ROUTES } from "../admin/admin-items.schemas.js";
3
3
  import { AUDIT_ROUTES } from "../admin/audit.schemas.js";
4
4
  import { ADMIN_EXTENSION_ROUTES } from "../admin/extensions.schemas.js";
5
+ import { OUTBOX_DEAD_ROUTES } from "../admin/outbox-dead.schemas.js";
5
6
  import { OVERVIEW_ROUTES } from "../admin/overview.schemas.js";
6
7
  import { AGENT_ROUTES } from "../agents/agents.schemas.js";
7
8
  import { AGENT_TEMPLATE_ROUTES } from "../agents/templates.schemas.js";
@@ -85,4 +86,6 @@ export const ROUTE_SCHEMAS = [
85
86
  // the admin overview and the platform-level audit log (admin overview spec §5.2)
86
87
  ...OVERVIEW_ROUTES,
87
88
  ...AUDIT_ROUTES,
89
+ // dead outbox rows (transactional outbox spec §3.4)
90
+ ...OUTBOX_DEAD_ROUTES,
88
91
  ];
@@ -1,9 +1,10 @@
1
- import { PluginScopeSyncProcessor } from "../catalog/scope-sync.js";
1
+ import { PluginScopeSyncProcessor } from "../catalog/scope-sync-workers.js";
2
2
  import { ChannelsProcessor } from "../channels/channels.module.js";
3
3
  import { ChannelOutbound } from "../channels/outbound.js";
4
4
  import { TitleQueue } from "../conversations/titles.js";
5
5
  import { EvalsProcessor } from "../evals/evals.module.js";
6
6
  import { EvalWorker } from "../evals/worker.js";
7
+ import { LifecycleHooksProcessor } from "../extensions/lifecycle-hooks.js";
7
8
  import { KernelConfigService } from "../infra/config/kernel-config.service.js";
8
9
  import { LockedIntervalScheduler } from "../infra/schedule/locked-interval.js";
9
10
  import { ScheduledRuns } from "../infra/schedule/scheduled-runs.js";
@@ -15,8 +16,8 @@ import { UsageReporter } from "../runtime/usage-report.js";
15
16
  /**
16
17
  * The worker role's parts, driven by `KernelLifecycle` at fixed points of its start order and stop
17
18
  * phases (so they stay ordered after the extension load and before the extension host closes): the
18
- * queue consumers (runs, sub-agent runs, evals, maintenance, the plugin scope sync, channel
19
- * deliveries, `usage.report`, titles) and the schedulers of the `@LockedCron` / `@LockedInterval` jobs. Provided only by
19
+ * queue consumers (runs, sub-agent runs, evals, maintenance, the plugin scope sync, lifecycle
20
+ * hook deliveries, channel deliveries, `usage.report`, titles) and the schedulers of the `@LockedCron` / `@LockedInterval` jobs. Provided only by
20
21
  * `WorkerModule`, so a process without the worker role has none of them.
21
22
  */
22
23
  export declare class WorkerRole {
@@ -36,13 +37,14 @@ export declare class WorkerRole {
36
37
  private readonly evalsProcessor;
37
38
  private readonly maintenanceProcessor;
38
39
  private readonly scopeProcessor;
40
+ private readonly lifecycleProcessor;
39
41
  /** The startup config (the roles). */
40
42
  private readonly config;
41
43
  /** The run worker was started: the runs phase drains it. */
42
44
  private runsStarted;
43
45
  /** The eval worker was started: the runs phase drains it. */
44
46
  private evalsStarted;
45
- constructor(config: KernelConfigService, log: KernelLogger, intervals: LockedIntervalScheduler, scheduledRuns: ScheduledRuns, runWorker: RunWorker, evalWorker: EvalWorker, usageReport: UsageReporter, titles: TitleQueue, channelOutbound: ChannelOutbound, runsProcessor: RunsProcessor, subagentRunsProcessor: SubagentRunsProcessor, usageProcessor: UsageReportProcessor, titleProcessor: TitleProcessor, channelsProcessor: ChannelsProcessor, evalsProcessor: EvalsProcessor, maintenanceProcessor: MaintenanceProcessor, scopeProcessor: PluginScopeSyncProcessor);
47
+ constructor(config: KernelConfigService, log: KernelLogger, intervals: LockedIntervalScheduler, scheduledRuns: ScheduledRuns, runWorker: RunWorker, evalWorker: EvalWorker, usageReport: UsageReporter, titles: TitleQueue, channelOutbound: ChannelOutbound, runsProcessor: RunsProcessor, subagentRunsProcessor: SubagentRunsProcessor, usageProcessor: UsageReportProcessor, titleProcessor: TitleProcessor, channelsProcessor: ChannelsProcessor, evalsProcessor: EvalsProcessor, maintenanceProcessor: MaintenanceProcessor, scopeProcessor: PluginScopeSyncProcessor, lifecycleProcessor: LifecycleHooksProcessor);
46
48
  /**
47
49
  * Starts the queue consumers (after the extension load), then opens the schedules' start gate:
48
50
  * the cron and interval timers were armed at application bootstrap, but every tick before this
@@ -60,6 +62,9 @@ export declare class WorkerRole {
60
62
  drainRuns(budgetMs: number): Promise<void> | undefined;
61
63
  /** The eval cases in progress stop (undefined: never started). */
62
64
  drainEvals(budgetMs: number): Promise<void> | undefined;
63
- /** Closes the maintenance queue's worker and the plugin scope sync's (it stops between pairs). */
65
+ /**
66
+ * Closes the maintenance queue's worker, the plugin scope sync's (it stops between pairs) and
67
+ * the lifecycle hook deliveries' (calls in flight are aborted and retried).
68
+ */
64
69
  closeMaintenance(): Promise<void>;
65
70
  }
@@ -8,12 +8,13 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
8
8
  return function (target, key) { decorator(target, key, paramIndex); }
9
9
  };
10
10
  import { Inject, Injectable } from "@nestjs/common";
11
- import { PluginScopeSyncProcessor } from "../catalog/scope-sync.js";
11
+ import { PluginScopeSyncProcessor } from "../catalog/scope-sync-workers.js";
12
12
  import { ChannelsProcessor } from "../channels/channels.module.js";
13
13
  import { ChannelOutbound } from "../channels/outbound.js";
14
14
  import { TitleQueue } from "../conversations/titles.js";
15
15
  import { EvalsProcessor } from "../evals/evals.module.js";
16
16
  import { EvalWorker } from "../evals/worker.js";
17
+ import { LifecycleHooksProcessor } from "../extensions/lifecycle-hooks.js";
17
18
  import { KernelConfigService } from "../infra/config/kernel-config.service.js";
18
19
  import { LockedIntervalScheduler } from "../infra/schedule/locked-interval.js";
19
20
  import { ScheduledRuns } from "../infra/schedule/scheduled-runs.js";
@@ -25,8 +26,8 @@ import { UsageReporter } from "../runtime/usage-report.js";
25
26
  /**
26
27
  * The worker role's parts, driven by `KernelLifecycle` at fixed points of its start order and stop
27
28
  * phases (so they stay ordered after the extension load and before the extension host closes): the
28
- * queue consumers (runs, sub-agent runs, evals, maintenance, the plugin scope sync, channel
29
- * deliveries, `usage.report`, titles) and the schedulers of the `@LockedCron` / `@LockedInterval` jobs. Provided only by
29
+ * queue consumers (runs, sub-agent runs, evals, maintenance, the plugin scope sync, lifecycle
30
+ * hook deliveries, channel deliveries, `usage.report`, titles) and the schedulers of the `@LockedCron` / `@LockedInterval` jobs. Provided only by
30
31
  * `WorkerModule`, so a process without the worker role has none of them.
31
32
  */
32
33
  let WorkerRole = class WorkerRole {
@@ -46,13 +47,14 @@ let WorkerRole = class WorkerRole {
46
47
  evalsProcessor;
47
48
  maintenanceProcessor;
48
49
  scopeProcessor;
50
+ lifecycleProcessor;
49
51
  /** The startup config (the roles). */
50
52
  config;
51
53
  /** The run worker was started: the runs phase drains it. */
52
54
  runsStarted = false;
53
55
  /** The eval worker was started: the runs phase drains it. */
54
56
  evalsStarted = false;
55
- constructor(config, log, intervals, scheduledRuns, runWorker, evalWorker, usageReport, titles, channelOutbound, runsProcessor, subagentRunsProcessor, usageProcessor, titleProcessor, channelsProcessor, evalsProcessor, maintenanceProcessor, scopeProcessor) {
57
+ constructor(config, log, intervals, scheduledRuns, runWorker, evalWorker, usageReport, titles, channelOutbound, runsProcessor, subagentRunsProcessor, usageProcessor, titleProcessor, channelsProcessor, evalsProcessor, maintenanceProcessor, scopeProcessor, lifecycleProcessor) {
56
58
  this.log = log;
57
59
  this.intervals = intervals;
58
60
  this.scheduledRuns = scheduledRuns;
@@ -69,6 +71,7 @@ let WorkerRole = class WorkerRole {
69
71
  this.evalsProcessor = evalsProcessor;
70
72
  this.maintenanceProcessor = maintenanceProcessor;
71
73
  this.scopeProcessor = scopeProcessor;
74
+ this.lifecycleProcessor = lifecycleProcessor;
72
75
  this.config = config.get();
73
76
  }
74
77
  /**
@@ -96,6 +99,7 @@ let WorkerRole = class WorkerRole {
96
99
  checkpoint();
97
100
  this.maintenanceProcessor.start();
98
101
  this.scopeProcessor.start();
102
+ this.lifecycleProcessor.start();
99
103
  this.channelOutbound.startWorker(this.channelsProcessor.worker);
100
104
  this.usageReport.startWorker(this.usageProcessor.worker);
101
105
  this.titles.startWorker(this.titleProcessor.worker);
@@ -105,8 +109,6 @@ let WorkerRole = class WorkerRole {
105
109
  // The gate opens: from here on ticks run; the runOnStart jobs run once now, in the background
106
110
  this.scheduledRuns.open();
107
111
  this.intervals.runStartJobs();
108
- // Every plugin's scope converges once per worker start (a failed or lost sync is retried)
109
- this.scopeProcessor.resync();
110
112
  }
111
113
  /**
112
114
  * Closes the start gate and stops the schedulers (no new tick; the runs in progress get the stop
@@ -123,9 +125,16 @@ let WorkerRole = class WorkerRole {
123
125
  drainEvals(budgetMs) {
124
126
  return this.evalsStarted ? this.evalWorker.close(budgetMs) : undefined;
125
127
  }
126
- /** Closes the maintenance queue's worker and the plugin scope sync's (it stops between pairs). */
128
+ /**
129
+ * Closes the maintenance queue's worker, the plugin scope sync's (it stops between pairs) and
130
+ * the lifecycle hook deliveries' (calls in flight are aborted and retried).
131
+ */
127
132
  async closeMaintenance() {
128
- await Promise.all([this.maintenanceProcessor.worker.close(), this.scopeProcessor.close()]);
133
+ await Promise.all([
134
+ this.maintenanceProcessor.worker.close(),
135
+ this.scopeProcessor.close(),
136
+ this.lifecycleProcessor.close(),
137
+ ]);
129
138
  }
130
139
  };
131
140
  WorkerRole = __decorate([
@@ -146,6 +155,7 @@ WorkerRole = __decorate([
146
155
  __param(13, Inject(ChannelsProcessor)),
147
156
  __param(14, Inject(EvalsProcessor)),
148
157
  __param(15, Inject(MaintenanceProcessor)),
149
- __param(16, Inject(PluginScopeSyncProcessor))
158
+ __param(16, Inject(PluginScopeSyncProcessor)),
159
+ __param(17, Inject(LifecycleHooksProcessor))
150
160
  ], WorkerRole);
151
161
  export { WorkerRole };
@@ -10,7 +10,6 @@ import { BackgroundModule } from "../background/background.module.js";
10
10
  import { BackgroundTaskPollJob } from "../background/poll.job.js";
11
11
  import { CatalogModule } from "../catalog/catalog.module.js";
12
12
  import { CatalogJobs } from "../catalog/jobs.js";
13
- import { PlatformMigration } from "../catalog/platform-migration.js";
14
13
  import { PluginScopeWorkersModule } from "../catalog/scope-sync-workers.js";
15
14
  import { ChannelsModule, ChannelWorkersModule } from "../channels/channels.module.js";
16
15
  import { GatewayCheckJob } from "../channels/supervisor.js";
@@ -24,17 +23,19 @@ import { LegacySandboxCleanupJob } from "../devices/legacy-cleanup.job.js";
24
23
  import { EvalWorkersModule } from "../evals/evals.module.js";
25
24
  import { ExtensionsModule } from "../extensions/extensions.module.js";
26
25
  import { PluginsReconcileJob } from "../extensions/lifecycle.js";
26
+ import { LifecycleHookWorkersModule } from "../extensions/lifecycle-hooks.js";
27
27
  import { InitialPasswordCleanupJob } from "../identity/initial-passwords.job.js";
28
+ import { OutboxRelayModule } from "../infra/outbox/outbox-relay.module.js";
28
29
  import { KernelScheduleModule } from "../infra/schedule/schedule.module.js";
29
30
  import { DirectoryScanJob } from "../orgs/directory-sync.js";
30
- import { OffboardSweepJob } from "../orgs/offboarding.js";
31
31
  import { OrgLockModule } from "../orgs/org-lock.js";
32
32
  import { OrgsModule } from "../orgs/orgs.module.js";
33
33
  import { MaintenanceModule } from "../runtime/maintenance.js";
34
+ import { RunJobsModule } from "../runtime/run-jobs.js";
35
+ import { RunOrphanCheck } from "../runtime/run-orphan-check.job.js";
34
36
  import { RuntimeWorkersModule } from "../runtime/run-processors.js";
35
37
  import { RuntimeModule } from "../runtime/runtime.module.js";
36
- import { UsageReportModule, UsageSweepJob } from "../runtime/usage-report.js";
37
- import { WaitSweepJob } from "../runtime/waits.js";
38
+ import { UsageReportModule } from "../runtime/usage-report.js";
38
39
  import { SandboxSweepJobs } from "../sandbox/jobs.js";
39
40
  import { SandboxModule } from "../sandbox/sandbox.module.js";
40
41
  import { ScheduledTaskFireModule } from "../schedules/fire.js";
@@ -58,6 +59,8 @@ let WorkerModule = WorkerModule_1 = class WorkerModule {
58
59
  module: WorkerModule_1,
59
60
  imports: [
60
61
  KernelScheduleModule,
62
+ // the outbox relay (`@LockedInterval`): delivers what the fast path did not
63
+ OutboxRelayModule,
61
64
  ClientModule,
62
65
  // the queue consumers (their worker options come from the startup config)
63
66
  RuntimeWorkersModule.forRoot(config),
@@ -65,8 +68,10 @@ let WorkerModule = WorkerModule_1 = class WorkerModule {
65
68
  ChannelWorkersModule.forRoot(config),
66
69
  MaintenanceModule,
67
70
  PluginScopeWorkersModule,
71
+ LifecycleHookWorkersModule,
68
72
  // the domains the fixed-period jobs call
69
73
  RuntimeModule,
74
+ RunJobsModule,
70
75
  UsageReportModule,
71
76
  TitlesModule,
72
77
  AttachmentsModule,
@@ -84,8 +89,8 @@ let WorkerModule = WorkerModule_1 = class WorkerModule {
84
89
  ScheduledTaskFireModule,
85
90
  ],
86
91
  providers: [
87
- WaitSweepJob,
88
- UsageSweepJob,
92
+ // the one repair of a run nobody runs (transactional outbox spec §8.3)
93
+ RunOrphanCheck,
89
94
  AttachmentCleanupJob,
90
95
  StoragePurgeJob,
91
96
  SandboxSweepJobs,
@@ -95,9 +100,7 @@ let WorkerModule = WorkerModule_1 = class WorkerModule {
95
100
  InitialPasswordCleanupJob,
96
101
  ClientReportsCron,
97
102
  CatalogJobs,
98
- PlatformMigration,
99
103
  DirectoryScanJob,
100
- OffboardSweepJob,
101
104
  PluginsReconcileJob,
102
105
  GatewayCheckJob,
103
106
  WorkerRole,
@@ -237,6 +237,9 @@ export declare function summaryText(summary: string): string;
237
237
  * summary: the latest one follows the summary) /
238
238
  * `run_context` (`role: "system"` at its position, `runContextText`; covered by the summary: the
239
239
  * current context follows the summary whole; a user message's sender line by `senderLines`) /
240
+ * `plugin_context` (`role: "system"` at its position, `pluginContextText`, nothing for empty
241
+ * text; covered by the summary: the latest non-empty one per plugin, in plugin-name order,
242
+ * follows the summary after `device_paths`) /
240
243
  * `background_task_finished`(`role: "system"`, the text of
241
244
  * {@link renderBackgroundFinished}, placed like a user_message)/ `subagent_delivery` (likewise,
242
245
  * the text of {@link renderSubagentDelivery});`tool_result` 事件还原为紧随其 assistant 消息之后的一条 user 消息
@@ -6,6 +6,7 @@ import { catalogText, isAlwaysLoaded } from "../../tools/builtins/tool-search.js
6
6
  import { renderSubagentDelivery } from "../subagents/render.js";
7
7
  import { devicePathsAt, devicePathsText } from "./device-paths.js";
8
8
  import { LEGACY_CATALOG_HEADER, LEGACY_SKILL_TEXTS, usesLegacyToolNames } from "./legacy-text.js";
9
+ import { pluginContextsAfterSummary, pluginContextText } from "./plugin-context.js";
9
10
  import { currentRunContext, runContextEvents, runContextFullText, runContextText, scheduleHeader, senderLines, } from "./run-context.js";
10
11
  import { invokedSkillNames, invokedSkillsText, SKILL_TEXTS, skillsCatalogEvents, snapshotChangeText, snapshotCurrentText, snapshotSystemText, systemSkillsCatalog, } from "./skills.js";
11
12
  import { toolsChangedText } from "./tool-changes.js";
@@ -341,6 +342,9 @@ export function summaryText(summary) {
341
342
  * summary: the latest one follows the summary) /
342
343
  * `run_context` (`role: "system"` at its position, `runContextText`; covered by the summary: the
343
344
  * current context follows the summary whole; a user message's sender line by `senderLines`) /
345
+ * `plugin_context` (`role: "system"` at its position, `pluginContextText`, nothing for empty
346
+ * text; covered by the summary: the latest non-empty one per plugin, in plugin-name order,
347
+ * follows the summary after `device_paths`) /
344
348
  * `background_task_finished`(`role: "system"`, the text of
345
349
  * {@link renderBackgroundFinished}, placed like a user_message)/ `subagent_delivery` (likewise,
346
350
  * the text of {@link renderSubagentDelivery});`tool_result` 事件还原为紧随其 assistant 消息之后的一条 user 消息
@@ -561,6 +565,10 @@ export function buildModelRequest(input) {
561
565
  if (paths) {
562
566
  messages.push({ role: "system", content: devicePathsText(paths.payload) });
563
567
  }
568
+ // memory spec §6.1: each plugin's context in effect at the boundary follows the summary again
569
+ for (const text of pluginContextsAfterSummary(events, after)) {
570
+ messages.push({ role: "system", content: text });
571
+ }
564
572
  // 被摘要覆盖的变更提醒不再发送:摘要时生效的目录与 system 里的不同 → 紧随摘要补上完整的当前目录
565
573
  const covered = skillSnaps.filter((e) => e.seq <= after).at(-1);
566
574
  // (phase B: plus the current pinned skills and tool-name map when they differ from system's)
@@ -639,6 +647,13 @@ export function buildModelRequest(input) {
639
647
  case "device_paths":
640
648
  messages.push({ role: "system", content: devicePathsText(e.payload) });
641
649
  break;
650
+ // a context@1 provider's text (memory spec §6.1); empty text (nothing any more) renders nothing
651
+ case "plugin_context": {
652
+ const text = pluginContextText(e.payload);
653
+ if (text !== "")
654
+ messages.push({ role: "system", content: text });
655
+ break;
656
+ }
642
657
  // hook_denied is not model-visible: the model sees only the denied tool call's tool_result
643
658
  // (and nothing for a denied model request), so request building skips it
644
659
  case "hook_denied":
@@ -0,0 +1,20 @@
1
+ import type { ConversationEvent, EventPayload } from "../../conversations/events.js";
2
+ /**
3
+ * The `plugin_context` event (memory spec §6.1): the text a `context@1` provider added to the
4
+ * conversation at a run start, written only when it changed. Model-visible: rendered at its
5
+ * position as a system message; after a summary that covers it, the latest non-empty one per
6
+ * plugin follows the summary again. Its text is in the log, so it needs no `DriftReason`.
7
+ */
8
+ /** The payload of a `plugin_context` event. */
9
+ export type PluginContextPayload = EventPayload<"plugin_context">;
10
+ /** The idempotency key of a run's `plugin_context` event for `plugin`. */
11
+ export declare const pluginContextIdemKey: (runId: string, plugin: string) => string;
12
+ /** The system message of a `plugin_context` event (empty text renders nothing: ""). */
13
+ export declare function pluginContextText(p: PluginContextPayload): string;
14
+ /** The latest `plugin_context` payload of each plugin at or before `uptoSeq`. */
15
+ export declare function latestPluginContexts(events: readonly ConversationEvent[], uptoSeq: number): Map<string, PluginContextPayload>;
16
+ /**
17
+ * The system messages that follow a summary covering up to `after`: the latest non-empty
18
+ * `plugin_context` of each plugin, in plugin-name order.
19
+ */
20
+ export declare function pluginContextsAfterSummary(events: readonly ConversationEvent[], after: number): string[];
@@ -0,0 +1,30 @@
1
+ /** The idempotency key of a run's `plugin_context` event for `plugin`. */
2
+ export const pluginContextIdemKey = (runId, plugin) => `plugin_context:${runId}:${plugin}`;
3
+ /** The system message of a `plugin_context` event (empty text renders nothing: ""). */
4
+ export function pluginContextText(p) {
5
+ if (p.text === "")
6
+ return "";
7
+ return `<plugin-context plugin="${p.plugin}">\n${p.text}\n</plugin-context>`;
8
+ }
9
+ /** The latest `plugin_context` payload of each plugin at or before `uptoSeq`. */
10
+ export function latestPluginContexts(events, uptoSeq) {
11
+ const latest = new Map();
12
+ for (const e of events) {
13
+ if (e.type !== "plugin_context" || e.seq > uptoSeq)
14
+ continue;
15
+ const prev = latest.get(e.payload.plugin);
16
+ if (!prev || e.seq > prev.seq)
17
+ latest.set(e.payload.plugin, { seq: e.seq, payload: e.payload });
18
+ }
19
+ return new Map([...latest].map(([plugin, v]) => [plugin, v.payload]));
20
+ }
21
+ /**
22
+ * The system messages that follow a summary covering up to `after`: the latest non-empty
23
+ * `plugin_context` of each plugin, in plugin-name order.
24
+ */
25
+ export function pluginContextsAfterSummary(events, after) {
26
+ return [...latestPluginContexts(events, after)]
27
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
28
+ .map(([, p]) => pluginContextText(p))
29
+ .filter((text) => text !== "");
30
+ }
@@ -94,7 +94,8 @@ export class LangGraphLoop {
94
94
  const config = {
95
95
  configurable: { thread_id: ctx.runId },
96
96
  // 每步最多 3 个超步(prepare、model、tools),再加 wrapUp 与余量。
97
- recursionLimit: ctx.limits.maxSteps * 3 + 10,
97
+ // no step limit: no recursion limit either (the loop ends when the model stops calling tools)
98
+ recursionLimit: ctx.limits.maxSteps === undefined ? Number.MAX_SAFE_INTEGER : ctx.limits.maxSteps * 3 + 10,
98
99
  durability: "sync",
99
100
  };
100
101
  const existing = await this.saver.getTuple({ configurable: { thread_id: ctx.runId } });
@@ -125,7 +126,12 @@ export class LangGraphLoop {
125
126
  : { kind: outcome, consumedUpToSeq: final.consumedUpToSeq };
126
127
  }
127
128
  build(ctx) {
128
- const timedOut = () => Date.now() >= ctx.limits.deadline;
129
+ // an absent limit is no limit (`runtime.maxSteps` / `runtime.maxRunSeconds` 0)
130
+ const { maxSteps } = ctx.limits;
131
+ const timedOut = () => {
132
+ const deadline = ctx.limits.deadline;
133
+ return deadline !== undefined && Date.now() >= deadline;
134
+ };
129
135
  // 本次运行的附件字节缓存:各步共用,运行结束即丢弃(只是优化,见 MediaCache)
130
136
  const mediaCache = new MediaCache(this.stepDeps.config.get().attachments.requestMediaBytes);
131
137
  const input = (step, absorbedUpToSeq) => ({
@@ -138,10 +144,11 @@ export class LangGraphLoop {
138
144
  signal: ctx.signal,
139
145
  sink: ctx.sink,
140
146
  absorbedUpToSeq,
141
- maxSteps: ctx.limits.maxSteps,
147
+ ...(maxSteps !== undefined && { maxSteps }),
142
148
  mediaCache,
143
149
  agentId: ctx.agentId,
144
150
  accountId: ctx.triggerAccountId,
151
+ source: ctx.source,
145
152
  ...(ctx.conversationKind !== undefined && { conversationKind: ctx.conversationKind }),
146
153
  ...(ctx.parent !== undefined && { parentRunId: ctx.parent.runId, parent: ctx.parent }),
147
154
  ...(ctx.subagent === true && { subagent: true }),
@@ -215,8 +222,11 @@ export class LangGraphLoop {
215
222
  agentVersion: ctx.agentVersion,
216
223
  agent: ctx.agent,
217
224
  accountId: ctx.triggerAccountId,
225
+ source: ctx.source,
226
+ ownerAccountId: ctx.ownerAccountId,
227
+ role: ctx.role,
218
228
  signal: ctx.signal,
219
- deadline: ctx.limits.deadline,
229
+ ...(ctx.limits.deadline !== undefined && { deadline: ctx.limits.deadline }),
220
230
  ...(ctx.conversationKind !== undefined && { conversationKind: ctx.conversationKind }),
221
231
  ...(ctx.parent !== undefined && { parent: ctx.parent }),
222
232
  });
@@ -256,7 +266,9 @@ export class LangGraphLoop {
256
266
  // (aborted / completed: a fork invocation's run ended in its first prepare, phase D)
257
267
  if (s.outcome !== null)
258
268
  return END;
259
- return s.budgetWrapUp === true || s.step > ctx.limits.maxSteps ? "wrapUp" : "model";
269
+ return s.budgetWrapUp === true || (maxSteps !== undefined && s.step > maxSteps)
270
+ ? "wrapUp"
271
+ : "model";
260
272
  }, ["model", "wrapUp", END])
261
273
  .addConditionalEdges("model", (s) => (s.budgetWrapUp === true ? "wrapUp" : s.outcome === null ? "tools" : END), ["tools", "wrapUp", END])
262
274
  .addEdge("tools", "prepare")
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Run limits where 0 means "no limit" (`runtime.maxSteps`, `runtime.maxRunSeconds`, a sub-agent's
3
+ * logged `maxSteps`): like Claude Code, a run without limits goes on until the model stops calling
4
+ * tools or someone stops it.
5
+ */
6
+ /**
7
+ * The tightest of the given limits, ignoring absent and non-positive ones (0 = no limit);
8
+ * `undefined` when none of them limits anything.
9
+ */
10
+ export declare function tightestLimit(...limits: (number | undefined)[]): number | undefined;
11
+ /**
12
+ * The run's deadline (epoch ms) for `runtime.maxRunSeconds` counted from `startMs`; `undefined`
13
+ * when the run has no duration limit (0).
14
+ */
15
+ export declare function runDeadline(startMs: number, maxRunSeconds: number): number | undefined;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Run limits where 0 means "no limit" (`runtime.maxSteps`, `runtime.maxRunSeconds`, a sub-agent's
3
+ * logged `maxSteps`): like Claude Code, a run without limits goes on until the model stops calling
4
+ * tools or someone stops it.
5
+ */
6
+ /**
7
+ * The tightest of the given limits, ignoring absent and non-positive ones (0 = no limit);
8
+ * `undefined` when none of them limits anything.
9
+ */
10
+ export function tightestLimit(...limits) {
11
+ let out;
12
+ for (const l of limits) {
13
+ if (l === undefined || !(l > 0))
14
+ continue;
15
+ out = out === undefined ? l : Math.min(out, l);
16
+ }
17
+ return out;
18
+ }
19
+ /**
20
+ * The run's deadline (epoch ms) for `runtime.maxRunSeconds` counted from `startMs`; `undefined`
21
+ * when the run has no duration limit (0).
22
+ */
23
+ export function runDeadline(startMs, maxRunSeconds) {
24
+ return maxRunSeconds > 0 ? startMs + maxRunSeconds * 1000 : undefined;
25
+ }
@@ -1,6 +1,8 @@
1
+ import type { ConversationSource } from "@capybara-hq/plugin-sdk";
1
2
  import type { AgentDefinition } from "../agents/definition.js";
2
3
  import type { KernelConfig } from "../config/schema.js";
3
4
  import type { AbsorbableEvent } from "../conversations/events.js";
5
+ import type { OrgRole } from "../orgs/roles.js";
4
6
  import type { StreamSink } from "./model-call.js";
5
7
  /** 一次运行交给 loop 的上下文(spec 4.4)。 */
6
8
  export interface LoopContext {
@@ -12,6 +14,12 @@ export interface LoopContext {
12
14
  agentId: string;
13
15
  /** 发起本次运行的人(对话发起人):工具调用用其个人凭据,审计记为 actor。 */
14
16
  triggerAccountId: string;
17
+ /** The conversation's source, read once per run (memory plugin spec §6.2). */
18
+ source: ConversationSource;
19
+ /** The conversation's owner (`conversations.account_id`); plugin tool handlers receive it. */
20
+ ownerAccountId: string;
21
+ /** The trigger account's org role when the run starts; plugin tool handlers receive it. */
22
+ role: OrgRole;
15
23
  agent: AgentDefinition;
16
24
  agentVersion: number;
17
25
  /** 用户中止或到达 deadline 时触发:进行中的模型调用立即停下。 */
@@ -27,9 +35,13 @@ export interface LoopContext {
27
35
  * 即 seq 也大于会话的 `consumed_seq`),按 seq 升序。loop 记录吸收到的最大 seq 作为 `consumedUpToSeq`。
28
36
  */
29
37
  pendingAbsorbable(afterSeq: number): Promise<AbsorbableEvent[]>;
38
+ /**
39
+ * The run's limits; an absent one is no limit (`runtime.maxSteps` / `runtime.maxRunSeconds` 0):
40
+ * `maxSteps` model steps before the final wrap-up, `deadline` in epoch ms.
41
+ */
30
42
  limits: {
31
- maxSteps: number;
32
- deadline: number;
43
+ maxSteps?: number;
44
+ deadline?: number;
33
45
  };
34
46
  /**
35
47
  * Kind of the conversation: plugin hooks fire for `chat` and `subagent` (F10, P-18, sub-agents
@@ -124,6 +136,7 @@ export interface AgentLoop {
124
136
  /**
125
137
  * The wait of a step whose sub-agents still run (spec §7.2): id `sa-<runId>-<step>`, expiring after
126
138
  * the approval timeout plus one run's duration plus 10 minutes (a child may itself wait for an
127
- * approval); the timeout is a safety net.
139
+ * approval); the timeout is a safety net. Without a run duration limit (`runtime.maxRunSeconds` 0)
140
+ * it is the approval timeout plus 10 minutes.
128
141
  */
129
142
  export declare function subagentsWait(runId: string, step: number, config: Pick<KernelConfig, "tools" | "runtime">, now?: number): WaitingFor;
@@ -8,7 +8,8 @@ export const subagentsWaitId = (runId, step) => `sa-${runId}-${step}`;
8
8
  /**
9
9
  * The wait of a step whose sub-agents still run (spec §7.2): id `sa-<runId>-<step>`, expiring after
10
10
  * the approval timeout plus one run's duration plus 10 minutes (a child may itself wait for an
11
- * approval); the timeout is a safety net.
11
+ * approval); the timeout is a safety net. Without a run duration limit (`runtime.maxRunSeconds` 0)
12
+ * it is the approval timeout plus 10 minutes.
12
13
  */
13
14
  export function subagentsWait(runId, step, config, now = Date.now()) {
14
15
  const ms = config.tools.approvalTimeoutHours * 3_600_000 + config.runtime.maxRunSeconds * 1000 + 600_000;