@capybara-hq/kernel 0.1.0-rc.22 → 0.1.0-rc.24

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 (234) hide show
  1. package/bootstrap.json +25 -25
  2. package/dist/admin/admin.controller.d.ts +3 -3
  3. package/dist/admin/admin.controller.js +6 -2
  4. package/dist/admin/admin.module.d.ts +2 -1
  5. package/dist/admin/admin.module.js +7 -3
  6. package/dist/admin/admin.schemas.d.ts +13 -0
  7. package/dist/admin/outbox-dead.controller.d.ts +23 -0
  8. package/dist/admin/outbox-dead.controller.js +62 -0
  9. package/dist/admin/outbox-dead.schemas.d.ts +8 -0
  10. package/dist/admin/outbox-dead.schemas.js +18 -0
  11. package/dist/admin/outbox-dead.service.d.ts +66 -0
  12. package/dist/admin/outbox-dead.service.js +179 -0
  13. package/dist/admin/overview.service.d.ts +40 -5
  14. package/dist/admin/overview.service.js +41 -7
  15. package/dist/agents/from-template.js +1 -1
  16. package/dist/background/finish.d.ts +5 -2
  17. package/dist/background/finish.js +14 -3
  18. package/dist/background/launch.d.ts +44 -5
  19. package/dist/background/launch.js +92 -9
  20. package/dist/background/session.d.ts +14 -2
  21. package/dist/background/session.js +26 -4
  22. package/dist/background/status.d.ts +1 -1
  23. package/dist/background/status.js +3 -3
  24. package/dist/background/stop.d.ts +0 -2
  25. package/dist/background/stop.js +1 -21
  26. package/dist/background/store.d.ts +8 -0
  27. package/dist/background/store.js +24 -0
  28. package/dist/catalog/admin-catalog.controller.d.ts +21 -2
  29. package/dist/catalog/admin-catalog.controller.js +45 -6
  30. package/dist/catalog/admin-catalog.schemas.d.ts +5 -0
  31. package/dist/catalog/admin-catalog.schemas.js +8 -0
  32. package/dist/catalog/catalog-content.d.ts +5 -0
  33. package/dist/catalog/catalog-content.js +1 -0
  34. package/dist/catalog/catalog.module.d.ts +2 -1
  35. package/dist/catalog/catalog.module.js +5 -1
  36. package/dist/catalog/marketplaces.service.d.ts +1 -1
  37. package/dist/catalog/platform-import-update.d.ts +50 -0
  38. package/dist/catalog/platform-import-update.js +116 -0
  39. package/dist/catalog/plugin-import.d.ts +36 -1
  40. package/dist/catalog/plugin-import.js +23 -1
  41. package/dist/catalog/plugin-upgrade.d.ts +18 -0
  42. package/dist/catalog/plugin-upgrade.js +19 -0
  43. package/dist/catalog/requests.service.js +2 -2
  44. package/dist/channels/channels.module.d.ts +5 -2
  45. package/dist/channels/channels.module.js +9 -2
  46. package/dist/channels/deliver-job.d.ts +25 -0
  47. package/dist/channels/deliver-job.js +25 -0
  48. package/dist/channels/inbound.d.ts +1 -1
  49. package/dist/channels/inbound.js +2 -15
  50. package/dist/channels/jobs.d.ts +28 -18
  51. package/dist/channels/jobs.js +63 -26
  52. package/dist/config/schema.d.ts +3 -6
  53. package/dist/config/schema.js +20 -27
  54. package/dist/conversations/agent-tree.d.ts +16 -0
  55. package/dist/conversations/agent-tree.js +36 -0
  56. package/dist/conversations/conversations.service.d.ts +44 -14
  57. package/dist/conversations/conversations.service.js +52 -38
  58. package/dist/conversations/event-log.d.ts +7 -10
  59. package/dist/conversations/event-log.js +24 -15
  60. package/dist/conversations/events.js +2 -1
  61. package/dist/conversations/queue.service.d.ts +8 -3
  62. package/dist/conversations/queue.service.js +37 -13
  63. package/dist/conversations/titles.d.ts +21 -8
  64. package/dist/conversations/titles.js +42 -15
  65. package/dist/db/kernel-schema.d.ts +26 -8
  66. package/dist/devices/devices.service.d.ts +12 -3
  67. package/dist/devices/devices.service.js +30 -9
  68. package/dist/errors.d.ts +15 -0
  69. package/dist/errors.js +15 -0
  70. package/dist/evals/run-replay.js +14 -8
  71. package/dist/extensions/extensions.module.js +3 -0
  72. package/dist/extensions/lifecycle.d.ts +6 -1
  73. package/dist/extensions/lifecycle.js +9 -2
  74. package/dist/extensions/usage-subscribers.d.ts +43 -0
  75. package/dist/extensions/usage-subscribers.js +108 -0
  76. package/dist/http/api.module.js +2 -0
  77. package/dist/identity/settings.d.ts +53 -3
  78. package/dist/identity/settings.js +92 -9
  79. package/dist/index.d.ts +1 -0
  80. package/dist/index.js +1 -0
  81. package/dist/infra/cli/kernel-cli.module.js +5 -0
  82. package/dist/infra/config/kernel-config.service.d.ts +7 -0
  83. package/dist/infra/config/kernel-config.service.js +20 -0
  84. package/dist/infra/events/kernel-events.d.ts +9 -35
  85. package/dist/infra/outbox/outbox-relay.module.d.ts +6 -0
  86. package/dist/infra/outbox/outbox-relay.module.js +18 -0
  87. package/dist/infra/outbox/outbox.dispatcher.d.ts +103 -0
  88. package/dist/infra/outbox/outbox.dispatcher.js +310 -0
  89. package/dist/infra/outbox/outbox.module.d.ts +24 -0
  90. package/dist/infra/outbox/outbox.module.js +50 -0
  91. package/dist/infra/outbox/outbox.relay.d.ts +31 -0
  92. package/dist/infra/outbox/outbox.relay.js +76 -0
  93. package/dist/infra/outbox/outbox.service.d.ts +51 -0
  94. package/dist/infra/outbox/outbox.service.js +131 -0
  95. package/dist/infra/outbox/registry.d.ts +120 -0
  96. package/dist/infra/outbox/registry.js +108 -0
  97. package/dist/infra/queue/queue-names.d.ts +8 -0
  98. package/dist/infra/queue/queue-names.js +16 -0
  99. package/dist/kernel.module.js +3 -0
  100. package/dist/local-devices/device-policy.service.d.ts +4 -0
  101. package/dist/local-devices/device-policy.service.js +61 -3
  102. package/dist/local-devices/local-device-gateway.d.ts +4 -2
  103. package/dist/local-devices/local-device-gateway.js +39 -14
  104. package/dist/local-devices/machines.d.ts +25 -1
  105. package/dist/local-devices/machines.js +91 -15
  106. package/dist/local-devices/policy-summary.d.ts +44 -1
  107. package/dist/local-devices/policy-summary.js +69 -0
  108. package/dist/models/embeddings.d.ts +9 -9
  109. package/dist/models/embeddings.js +11 -18
  110. package/dist/models/models.module.js +3 -0
  111. package/dist/orgs/orgs.service.js +7 -0
  112. package/dist/orgs/settings.controller.js +2 -2
  113. package/dist/orgs/settings.service.d.ts +11 -5
  114. package/dist/orgs/settings.service.js +28 -14
  115. package/dist/overrides.d.ts +20 -3
  116. package/dist/overrides.js +10 -2
  117. package/dist/platform/exclusions.js +5 -0
  118. package/dist/platform/ops/admin.ops.js +50 -9
  119. package/dist/platform/ops/catalog-admin.ops.d.ts +3 -1
  120. package/dist/platform/ops/catalog-admin.ops.js +32 -4
  121. package/dist/platform/ops/org-settings.ops.js +3 -3
  122. package/dist/platform/ops/orgs.ops.js +1 -0
  123. package/dist/platform/ops/outbox.ops.d.ts +21 -0
  124. package/dist/platform/ops/outbox.ops.js +125 -0
  125. package/dist/platform/ops/platform.ops.js +1 -1
  126. package/dist/platform/ops/schedules.ops.js +40 -1
  127. package/dist/platform/platform-ops.module.d.ts +2 -1
  128. package/dist/platform/platform-ops.module.js +3 -0
  129. package/dist/platform/route-schemas.js +3 -0
  130. package/dist/roles/worker.module.js +9 -4
  131. package/dist/runtime/langgraph-loop.js +13 -5
  132. package/dist/runtime/limits.d.ts +15 -0
  133. package/dist/runtime/limits.js +25 -0
  134. package/dist/runtime/loop.d.ts +8 -3
  135. package/dist/runtime/loop.js +2 -1
  136. package/dist/runtime/maintenance.d.ts +4 -2
  137. package/dist/runtime/maintenance.js +17 -2
  138. package/dist/runtime/model-call.d.ts +14 -16
  139. package/dist/runtime/model-call.js +14 -24
  140. package/dist/runtime/queue-lost-jobs.d.ts +24 -0
  141. package/dist/runtime/queue-lost-jobs.js +51 -0
  142. package/dist/runtime/run-control.d.ts +42 -5
  143. package/dist/runtime/run-control.js +66 -12
  144. package/dist/runtime/run-finish.d.ts +39 -12
  145. package/dist/runtime/run-finish.js +97 -14
  146. package/dist/runtime/run-jobs.d.ts +95 -13
  147. package/dist/runtime/run-jobs.js +199 -28
  148. package/dist/runtime/run-orphan-check.job.d.ts +142 -0
  149. package/dist/runtime/run-orphan-check.job.js +339 -0
  150. package/dist/runtime/run-processors.d.ts +16 -9
  151. package/dist/runtime/run-processors.js +1 -1
  152. package/dist/runtime/run-queue.d.ts +64 -55
  153. package/dist/runtime/run-queue.js +147 -284
  154. package/dist/runtime/run-steps.d.ts +1 -2
  155. package/dist/runtime/run-steps.js +8 -11
  156. package/dist/runtime/run-worker.d.ts +6 -17
  157. package/dist/runtime/run-worker.js +32 -34
  158. package/dist/runtime/runtime.module.d.ts +2 -3
  159. package/dist/runtime/runtime.module.js +5 -6
  160. package/dist/runtime/step-log.d.ts +16 -4
  161. package/dist/runtime/step-log.js +26 -6
  162. package/dist/runtime/stream.controller.d.ts +2 -4
  163. package/dist/runtime/stream.controller.js +5 -11
  164. package/dist/runtime/subagents/child.js +1 -1
  165. package/dist/runtime/subagents/definition.d.ts +2 -1
  166. package/dist/runtime/subagents/definition.js +4 -2
  167. package/dist/runtime/subagents/deliveries.d.ts +6 -3
  168. package/dist/runtime/subagents/deliveries.js +16 -7
  169. package/dist/runtime/subagents/dispatch.d.ts +12 -12
  170. package/dist/runtime/subagents/dispatch.js +13 -38
  171. package/dist/runtime/subagents/messages.d.ts +5 -1
  172. package/dist/runtime/subagents/messages.js +11 -3
  173. package/dist/runtime/subagents/skill-fork.d.ts +3 -3
  174. package/dist/runtime/subagents/skill-fork.js +5 -5
  175. package/dist/runtime/subagents/subagents.service.js +1 -1
  176. package/dist/runtime/subagents/tree-jobs.d.ts +61 -0
  177. package/dist/runtime/subagents/tree-jobs.js +86 -0
  178. package/dist/runtime/usage-report-jobs.d.ts +23 -48
  179. package/dist/runtime/usage-report-jobs.js +67 -119
  180. package/dist/runtime/usage-report.d.ts +28 -77
  181. package/dist/runtime/usage-report.js +35 -213
  182. package/dist/runtime/waits.d.ts +48 -198
  183. package/dist/runtime/waits.js +103 -805
  184. package/dist/sandbox/platform-tiers.d.ts +86 -0
  185. package/dist/sandbox/platform-tiers.js +97 -0
  186. package/dist/sandbox/sandbox.service.d.ts +18 -5
  187. package/dist/sandbox/sandbox.service.js +75 -20
  188. package/dist/sandbox/tiers.d.ts +14 -2
  189. package/dist/sandbox/tiers.js +8 -0
  190. package/dist/schedules/calendar.d.ts +134 -0
  191. package/dist/schedules/calendar.js +410 -0
  192. package/dist/schedules/fire.d.ts +1 -3
  193. package/dist/schedules/fire.js +5 -10
  194. package/dist/schedules/run-tracker.d.ts +0 -5
  195. package/dist/schedules/run-tracker.js +0 -13
  196. package/dist/schedules/scan.job.js +15 -20
  197. package/dist/schedules/schedule-math.d.ts +42 -0
  198. package/dist/schedules/schedule-math.js +52 -0
  199. package/dist/schedules/scheduled-tasks.service.d.ts +16 -0
  200. package/dist/schedules/scheduled-tasks.service.js +53 -0
  201. package/dist/schedules/schedules.controller.d.ts +5 -1
  202. package/dist/schedules/schedules.controller.js +15 -1
  203. package/dist/schedules/schedules.schemas.d.ts +35 -0
  204. package/dist/schedules/schedules.schemas.js +27 -0
  205. package/dist/schedules/store.d.ts +5 -0
  206. package/dist/schedules/store.js +20 -0
  207. package/dist/tools/approvals.service.d.ts +26 -7
  208. package/dist/tools/approvals.service.js +88 -10
  209. package/dist/tools/builtin-names.d.ts +5 -3
  210. package/dist/tools/builtin-names.js +12 -4
  211. package/dist/tools/builtins/builtin-tools.d.ts +1 -2
  212. package/dist/tools/builtins/builtin-tools.js +21 -17
  213. package/dist/tools/builtins/sandbox/bash.js +9 -3
  214. package/dist/tools/builtins/sandbox/common.d.ts +18 -1
  215. package/dist/tools/builtins/sandbox/common.js +14 -1
  216. package/dist/tools/builtins/sandbox/index.d.ts +2 -1
  217. package/dist/tools/builtins/sandbox/index.js +4 -1
  218. package/dist/tools/builtins/sandbox/task-list.d.ts +12 -0
  219. package/dist/tools/builtins/sandbox/task-list.js +130 -0
  220. package/dist/tools/builtins/sandbox/task-output.d.ts +8 -1
  221. package/dist/tools/builtins/sandbox/task-output.js +21 -3
  222. package/dist/tools/builtins/web/extract.d.ts +2 -4
  223. package/dist/tools/builtins/web/extract.js +2 -5
  224. package/dist/tools/pipeline.d.ts +1 -1
  225. package/dist/tools/pipeline.js +1 -1
  226. package/dist/tools/questions.service.d.ts +15 -6
  227. package/dist/tools/questions.service.js +20 -8
  228. package/dist/tools/registry.d.ts +4 -2
  229. package/dist/tools/registry.js +4 -3
  230. package/dist/tools/tools.module.js +4 -3
  231. package/package.json +3 -3
  232. package/src/migrations/0118_device_policy_ops.sql +6 -0
  233. package/src/migrations/0119_outbox.sql +22 -0
  234. package/src/migrations/0120_drop_usage_report_sweep.sql +7 -0
@@ -24,6 +24,7 @@ import { LockService } from "../infra/lock/lock.service.js";
24
24
  import { WithLock } from "../infra/lock/with-lock.decorator.js";
25
25
  import { DevicePolicyService } from "../local-devices/device-policy.service.js";
26
26
  import { ORG_ROLES, roleAtLeast } from "../orgs/roles.js";
27
+ import { RunResume } from "../runtime/run-jobs.js";
27
28
  import { rootConversationOf } from "../runtime/subagents/child.js";
28
29
  import { SandboxService } from "../sandbox/sandbox.service.js";
29
30
  import { readScheduleSettings } from "../schedules/effective-settings.js";
@@ -102,10 +103,12 @@ function canHandle(a, initiator, accountId, role) {
102
103
  * 工具调用审批:新建(loop 调用)、列出 / 查看 / 处理(HTTP),以及「以后都允许」授权的查看与撤销。
103
104
  * 状态全部在 PG:处理决定在事务里 `SELECT … FOR UPDATE` 审批行,多副本并发处理同一审批时恰好一个生效。
104
105
  *
105
- * A decision is announced after the commit as the domain event `approval.decided` (exactly once:
106
- * only the decision that changed the row from pending), which the run's waits follow to resume it
107
- * (spec §3b; the wait sweep resumes a run whose resume was lost). Events are appended in the
108
- * context's transaction (`EventLog.appendIn`) and published after the commit.
106
+ * A decision resumes its waiting run in the decision's transaction (`RunResume.resumeIn`, after the
107
+ * decided row: lock order approval, then run; transactional outbox spec §6). It is announced after
108
+ * the commit as the domain event `approval.decided` (exactly once: only the decision that changed
109
+ * the row from pending; no kernel subscriber: the IM card update is owed by the `approval_decided`
110
+ * append, transactional outbox spec §8.1). Events are appended in the context's transaction
111
+ * (`EventLog.appendIn`) and published after the commit.
109
112
  */
110
113
  let ApprovalsService = class ApprovalsService {
111
114
  db;
@@ -118,6 +121,7 @@ let ApprovalsService = class ApprovalsService {
118
121
  policies;
119
122
  lockService;
120
123
  sandbox;
124
+ resumes;
121
125
  constructor(db, config, eventLog, events, txHost, schedules,
122
126
  /** A trial approval is kept only for a tool the task may hold as a grant (its agent's tools). */
123
127
  registry,
@@ -126,7 +130,9 @@ let ApprovalsService = class ApprovalsService {
126
130
  /** One decision of a network ask at a time, across replicas (the op is sent before the transaction). */
127
131
  lockService,
128
132
  /** A trial run's 「这次允许」 becomes a task grant only within the org's egress. */
129
- sandbox) {
133
+ sandbox,
134
+ /** A decision resumes its waiting run in the decision's transaction. */
135
+ resumes) {
130
136
  this.db = db;
131
137
  this.config = config;
132
138
  this.eventLog = eventLog;
@@ -137,6 +143,7 @@ let ApprovalsService = class ApprovalsService {
137
143
  this.policies = policies;
138
144
  this.lockService = lockService;
139
145
  this.sandbox = sandbox;
146
+ this.resumes = resumes;
140
147
  }
141
148
  /**
142
149
  * 新建 pending 审批(`expires_at` = 现在 + `tools.approvalTimeoutHours`)并写 `approval_requested`,同一事务。
@@ -549,7 +556,7 @@ let ApprovalsService = class ApprovalsService {
549
556
  /** After the commit: the decision's events reach the page, the run's waits and IM delivery. */
550
557
  async announceDecided(record, toSeq) {
551
558
  await this.eventLog.notify(record.conversationId, toSeq);
552
- // waits resume the run and its IM delivery is enqueued (handler failures are logged)
559
+ // its IM delivery is enqueued (handler failures are logged); the run resumed in the decision
553
560
  await this.events.emit("approval.decided", {
554
561
  id: record.id,
555
562
  orgId: record.orgId,
@@ -571,6 +578,9 @@ let ApprovalsService = class ApprovalsService {
571
578
  // decision committed, even when a caller has a transaction open
572
579
  async decideIn(orgId, id, accountId, body, actorTokenId, network) {
573
580
  const t = this.db.db;
581
+ // lock order: the conversation, the approval, then the run (as a stop of the waiting run)
582
+ if (!(await this.lockConversationOf(id, orgId)))
583
+ throw notFound();
574
584
  const locked = await t
575
585
  .selectFrom("approvals")
576
586
  .selectAll()
@@ -734,6 +744,7 @@ let ApprovalsService = class ApprovalsService {
734
744
  ...(reason !== undefined && { reason }),
735
745
  },
736
746
  });
747
+ await this.resumes.resumeIn(before.runId, id);
737
748
  return { record: toRecord(updated), toSeq: Math.max(...written.map((e) => e.seq)) };
738
749
  }
739
750
  await audit(t, {
@@ -754,6 +765,9 @@ let ApprovalsService = class ApprovalsService {
754
765
  ...(reason !== undefined && { reason }),
755
766
  },
756
767
  });
768
+ // the run last (lock order: the decided row, then `runs`); a still-running run is resumed by
769
+ // its suspend's re-check
770
+ await this.resumes.resumeIn(before.runId, id);
757
771
  return { record: toRecord(updated), toSeq: Math.max(...written.map((e) => e.seq)) };
758
772
  }
759
773
  /**
@@ -908,6 +922,8 @@ let ApprovalsService = class ApprovalsService {
908
922
  }
909
923
  async expireIn(id) {
910
924
  const t = this.db.db;
925
+ if (!(await this.lockConversationOf(id)))
926
+ return { outcome: "settled" };
911
927
  const locked = await t
912
928
  .selectFrom("approvals")
913
929
  .selectAll()
@@ -965,10 +981,22 @@ let ApprovalsService = class ApprovalsService {
965
981
  */
966
982
  async cancelPendingFor(orgId, accountId) {
967
983
  const t = this.db.db;
984
+ // the conversations first, in id order (lock order: conversation, then approval rows)
985
+ const convs = await this.lockConversations(t
986
+ .selectFrom("approvals")
987
+ .select("conversation_id")
988
+ .where("org_id", "=", orgId)
989
+ .where("requested_for", "=", accountId)
990
+ .where("status", "=", "pending"));
991
+ // only the conversations locked above: an approval asked meanwhile in another one is left to
992
+ // the run's stop or the sweep, so no conversation is locked after a row
993
+ if (convs.length === 0)
994
+ return { records: [], seqs: new Map() };
968
995
  const rows = await t
969
996
  .selectFrom("approvals")
970
997
  .selectAll()
971
998
  .where("org_id", "=", orgId)
999
+ .where("conversation_id", "in", convs)
972
1000
  .where("requested_for", "=", accountId)
973
1001
  .where("status", "=", "pending")
974
1002
  .orderBy("created_at")
@@ -996,17 +1024,29 @@ let ApprovalsService = class ApprovalsService {
996
1024
  * active runs `authorAccountId` started, in the conversation and in its sub-agents'
997
1025
  * conversations at any depth (their asks are shown in the root). Each becomes `skipped` with
998
1026
  * `approval_decided{skipped}` by the author; access stays blocked. Returns the skipped records and
999
- * the highest seq written per conversation; the caller notifies and emits
1000
- * `approval.decided{skipped}` after the commit, so the runs resume.
1027
+ * the highest seq written per conversation; the caller resumes their waiting runs in this
1028
+ * transaction once every skipped row is locked (`ConversationsService.skipWaitsIn`), and notifies
1029
+ * and emits the domain event `approval.decided{skipped}` after the commit (its IM card update is
1030
+ * owed by the append, transactional outbox spec §8.1).
1001
1031
  */
1002
1032
  async skipNetworkIn(conversationId, authorAccountId) {
1003
1033
  const t = this.db.db;
1004
1034
  const tree = await this.subtreeOf(conversationId);
1035
+ // the sub-agents' conversations with a pending ask first, in id order (lock order:
1036
+ // conversation, then approval rows; the caller holds `conversationId`'s already)
1037
+ const convs = await this.lockConversations(t
1038
+ .selectFrom("approvals")
1039
+ .select("conversation_id")
1040
+ .where("conversation_id", "in", tree)
1041
+ .where("kind", "=", "network")
1042
+ .where("status", "=", "pending"));
1043
+ if (convs.length === 0)
1044
+ return { records: [], seqs: new Map() };
1005
1045
  const rows = await t
1006
1046
  .selectFrom("approvals as a")
1007
1047
  .innerJoin("runs as r", "r.id", "a.run_id")
1008
1048
  .selectAll("a")
1009
- .where("a.conversation_id", "in", tree)
1049
+ .where("a.conversation_id", "in", convs)
1010
1050
  .where("a.kind", "=", "network")
1011
1051
  .where("a.status", "=", "pending")
1012
1052
  .where(sql `a.expires_at > now()`)
@@ -1031,6 +1071,43 @@ let ApprovalsService = class ApprovalsService {
1031
1071
  }
1032
1072
  return { records, seqs };
1033
1073
  }
1074
+ /**
1075
+ * Locks the conversation row of approval `id` (`SELECT … FOR UPDATE`; re-entrant with the lock
1076
+ * `EventLog.appendIn` takes later). Every write to an approval row takes its conversation's lock
1077
+ * first, then the approval row, then the run row, as the stop of a waiting run
1078
+ * (`Waits.abortWaitingIn`) and the questions do, so no two of them can deadlock. False: no such
1079
+ * approval (in `orgId`).
1080
+ */
1081
+ async lockConversationOf(id, orgId) {
1082
+ const t = this.db.db;
1083
+ let q = t.selectFrom("approvals").select("conversation_id").where("id", "=", id);
1084
+ if (orgId !== undefined)
1085
+ q = q.where("org_id", "=", orgId);
1086
+ const row = await q.executeTakeFirst();
1087
+ if (!row)
1088
+ return false;
1089
+ await t
1090
+ .selectFrom("conversations")
1091
+ .select("id")
1092
+ .where("id", "=", row.conversation_id)
1093
+ .forUpdate()
1094
+ .executeTakeFirst();
1095
+ return true;
1096
+ }
1097
+ /** Locks, in id order, the conversations `ids` selects; returns their ids. */
1098
+ async lockConversations(ids) {
1099
+ const found = [...new Set((await ids.execute()).map((r) => r.conversation_id))];
1100
+ if (found.length === 0)
1101
+ return [];
1102
+ const rows = await this.db.db
1103
+ .selectFrom("conversations")
1104
+ .select("id")
1105
+ .where("id", "in", found)
1106
+ .orderBy("id")
1107
+ .forUpdate()
1108
+ .execute();
1109
+ return rows.map((r) => r.id);
1110
+ }
1034
1111
  /** `conversationId` and its sub-agents' conversations at any depth (at most 16 levels). */
1035
1112
  async subtreeOf(conversationId) {
1036
1113
  const all = [conversationId];
@@ -1252,6 +1329,7 @@ ApprovalsService = __decorate([
1252
1329
  __param(6, Inject(ToolRegistry)),
1253
1330
  __param(7, Inject(DevicePolicyService)),
1254
1331
  __param(8, Inject(LockService)),
1255
- __param(9, Inject(SandboxService))
1332
+ __param(9, Inject(SandboxService)),
1333
+ __param(10, Inject(RunResume))
1256
1334
  ], ApprovalsService);
1257
1335
  export { ApprovalsService };
@@ -23,6 +23,7 @@ export declare const BUILTIN: {
23
23
  readonly SubagentHandback: "SubagentHandback";
24
24
  readonly TaskOutput: "TaskOutput";
25
25
  readonly TaskStop: "TaskStop";
26
+ readonly TaskList: "TaskList";
26
27
  readonly WebSearch: "WebSearch";
27
28
  readonly WebFetch: "WebFetch";
28
29
  readonly Platform: "Platform";
@@ -35,7 +36,8 @@ export declare const BUILTIN: {
35
36
  export type BuiltinName = (typeof BUILTIN)[keyof typeof BUILTIN];
36
37
  /**
37
38
  * The builtin tools that run in the conversation's sandbox. `TaskOutput` and `TaskStop` read and
38
- * stop the background tasks `Bash` started (background Bash spec §2.2, §2.3).
39
+ * stop the background tasks `Bash` started (background Bash spec §2.2, §2.3); `TaskList` lists them
40
+ * (and the conversation's sub-agents).
39
41
  */
40
42
  export declare const SANDBOX_TOOL_NAMES: readonly BuiltinName[];
41
43
  /** The builtin tools that reach the web through the org's web-search / web-fetch providers. */
@@ -47,7 +49,7 @@ export declare const WEB_TOOL_NAMES: readonly BuiltinName[];
47
49
  export declare const BASH_COMPANION_TOOLS: readonly BuiltinName[];
48
50
  /**
49
51
  * Sandbox tools that need approval when the org setting `sandboxToolPolicy` is `ask` (not the
50
- * read-only ones). Not `TaskOutput` or `TaskStop`: they only read or stop a task whose launch
52
+ * read-only ones). Not `TaskOutput`, `TaskStop` or `TaskList`: they only read, list or stop tasks whose launch
51
53
  * already went through `Bash`'s policy (background Bash spec §4.5).
52
54
  */
53
55
  export declare const SANDBOX_ASK_TOOL_NAMES: ReadonlySet<string>;
@@ -110,7 +112,7 @@ export declare const CHILD_REMOVED_TOOLS: readonly ["AskUserQuestion", "Deliver"
110
112
  /**
111
113
  * The builtins every agent has unless it turns them off (tools default-on spec §4), in this
112
114
  * order: {@link BUILTIN_TOOL_NAMES} without the ones the registry manages by rule (`ToolSearch`,
113
- * `Skill`, `SendMessage`, `SubagentHandback`) and without `TaskOutput` / `TaskStop`, which come
115
+ * `Skill`, `SendMessage`, `SubagentHandback`) and without `TaskOutput` / `TaskStop` / `TaskList`, which come
114
116
  * with `Bash` ({@link BASH_COMPANION_TOOLS}). These are also the builtins an agent can turn off.
115
117
  */
116
118
  export declare const AGENT_BUILTIN_NAMES: readonly BuiltinName[];
@@ -23,6 +23,7 @@ export const BUILTIN = {
23
23
  SubagentHandback: "SubagentHandback",
24
24
  TaskOutput: "TaskOutput",
25
25
  TaskStop: "TaskStop",
26
+ TaskList: "TaskList",
26
27
  WebSearch: "WebSearch",
27
28
  WebFetch: "WebFetch",
28
29
  Platform: "Platform",
@@ -34,7 +35,8 @@ export const BUILTIN = {
34
35
  };
35
36
  /**
36
37
  * The builtin tools that run in the conversation's sandbox. `TaskOutput` and `TaskStop` read and
37
- * stop the background tasks `Bash` started (background Bash spec §2.2, §2.3).
38
+ * stop the background tasks `Bash` started (background Bash spec §2.2, §2.3); `TaskList` lists them
39
+ * (and the conversation's sub-agents).
38
40
  */
39
41
  export const SANDBOX_TOOL_NAMES = [
40
42
  BUILTIN.Bash,
@@ -46,6 +48,7 @@ export const SANDBOX_TOOL_NAMES = [
46
48
  BUILTIN.Deliver,
47
49
  BUILTIN.TaskOutput,
48
50
  BUILTIN.TaskStop,
51
+ BUILTIN.TaskList,
49
52
  ];
50
53
  /** The builtin tools that reach the web through the org's web-search / web-fetch providers. */
51
54
  export const WEB_TOOL_NAMES = [BUILTIN.WebSearch, BUILTIN.WebFetch];
@@ -53,10 +56,14 @@ export const WEB_TOOL_NAMES = [BUILTIN.WebSearch, BUILTIN.WebFetch];
53
56
  * The tools offered with `Bash` whenever it is offered (background Bash: a model that can start a
54
57
  * background task can read and stop it). `ToolRegistry` adds them; an explicit ref is harmless.
55
58
  */
56
- export const BASH_COMPANION_TOOLS = [BUILTIN.TaskOutput, BUILTIN.TaskStop];
59
+ export const BASH_COMPANION_TOOLS = [
60
+ BUILTIN.TaskOutput,
61
+ BUILTIN.TaskStop,
62
+ BUILTIN.TaskList,
63
+ ];
57
64
  /**
58
65
  * Sandbox tools that need approval when the org setting `sandboxToolPolicy` is `ask` (not the
59
- * read-only ones). Not `TaskOutput` or `TaskStop`: they only read or stop a task whose launch
66
+ * read-only ones). Not `TaskOutput`, `TaskStop` or `TaskList`: they only read, list or stop tasks whose launch
60
67
  * already went through `Bash`'s policy (background Bash spec §4.5).
61
68
  */
62
69
  export const SANDBOX_ASK_TOOL_NAMES = new Set([
@@ -158,7 +165,7 @@ export const CHILD_REMOVED_TOOLS = [
158
165
  /**
159
166
  * The builtins every agent has unless it turns them off (tools default-on spec §4), in this
160
167
  * order: {@link BUILTIN_TOOL_NAMES} without the ones the registry manages by rule (`ToolSearch`,
161
- * `Skill`, `SendMessage`, `SubagentHandback`) and without `TaskOutput` / `TaskStop`, which come
168
+ * `Skill`, `SendMessage`, `SubagentHandback`) and without `TaskOutput` / `TaskStop` / `TaskList`, which come
162
169
  * with `Bash` ({@link BASH_COMPANION_TOOLS}). These are also the builtins an agent can turn off.
163
170
  */
164
171
  export const AGENT_BUILTIN_NAMES = BUILTIN_TOOL_NAMES.filter((n) => n !== BUILTIN.ToolSearch &&
@@ -177,6 +184,7 @@ export const BUILTIN_TOOL_KINDS = {
177
184
  [BUILTIN.Deliver]: "tool",
178
185
  [BUILTIN.TaskOutput]: "read",
179
186
  [BUILTIN.TaskStop]: "command",
187
+ [BUILTIN.TaskList]: "read",
180
188
  [BUILTIN.ToolSearch]: "meta",
181
189
  [BUILTIN.Skill]: "meta",
182
190
  [BUILTIN.ReadToolOutput]: "meta",
@@ -14,7 +14,6 @@ import { AgentDocs } from "../../platform/agent-docs.js";
14
14
  import { PlatformOperations } from "../../platform/registry.js";
15
15
  import type { HookRunner } from "../../runtime/hook-calls.js";
16
16
  import { StepLog } from "../../runtime/step-log.js";
17
- import { UsageReporter } from "../../runtime/usage-report.js";
18
17
  import { SandboxService } from "../../sandbox/sandbox.service.js";
19
18
  import { ScheduledTaskStore } from "../../schedules/store.js";
20
19
  import { StorageService } from "../../storage/storage.service.js";
@@ -34,7 +33,7 @@ export declare class BuiltinTools {
34
33
  /** The WebFetch extraction call: the `web_fetch` purpose, its hooks, usage and denials. */
35
34
  purposes: ModelPurposesService, host: {
36
35
  readonly hooks?: HookRunner;
37
- } | undefined, usageReport: UsageReporter, stepLog: StepLog, log: Logger, background: BackgroundTaskStore, finisher: BackgroundTaskFinisher, stopper: BackgroundTaskStopper, platformOps: PlatformOperations, platformActor: PlatformActor, agentDocs: AgentDocs,
36
+ } | undefined, stepLog: StepLog, log: Logger, background: BackgroundTaskStore, finisher: BackgroundTaskFinisher, stopper: BackgroundTaskStopper, platformOps: PlatformOperations, platformActor: PlatformActor, agentDocs: AgentDocs,
38
37
  /** The schedule tools read tasks and grants; their writes go through the task service. */
39
38
  scheduleStore: ScheduledTaskStore,
40
39
  /** `ScheduleUpdate`'s write: its field change and grant changes in one transaction. */
@@ -11,8 +11,10 @@ import { Inject, Injectable, Optional } from "@nestjs/common";
11
11
  import { BackgroundTaskFinisher } from "../../background/finish.js";
12
12
  import { BackgroundTaskStopper } from "../../background/stop.js";
13
13
  import { BackgroundTaskStore } from "../../background/store.js";
14
+ import { readChildAgents } from "../../conversations/agent-tree.js";
14
15
  import { AttachmentsService } from "../../conversations/attachments.service.js";
15
16
  import { EventLog } from "../../conversations/event-log.js";
17
+ import { conversationAncestors } from "../../conversations/tree.js";
16
18
  import { ConversationDevices } from "../../devices/conversation-devices.js";
17
19
  import { ExtensionHost } from "../../extensions/host.js";
18
20
  import { ExtensionPointDefaults } from "../../extensions/point-defaults.js";
@@ -26,7 +28,6 @@ import { AgentDocs } from "../../platform/agent-docs.js";
26
28
  import { PlatformOperations } from "../../platform/registry.js";
27
29
  import { conversationTimeZone, RUN_CONTEXT_CLOCK } from "../../runtime/run-context.service.js";
28
30
  import { StepLog } from "../../runtime/step-log.js";
29
- import { UsageReporter } from "../../runtime/usage-report.js";
30
31
  import { SandboxService } from "../../sandbox/sandbox.service.js";
31
32
  import { ScheduledTaskStore } from "../../schedules/store.js";
32
33
  import { StorageService } from "../../storage/storage.service.js";
@@ -53,7 +54,7 @@ let BuiltinTools = class BuiltinTools {
53
54
  tools;
54
55
  constructor(db, config, outputs, storage, attachments, eventLog, sandbox, devices, points, webPages,
55
56
  /** The WebFetch extraction call: the `web_fetch` purpose, its hooks, usage and denials. */
56
- purposes, host, usageReport, stepLog, log, background, finisher, stopper, platformOps, platformActor, agentDocs,
57
+ purposes, host, stepLog, log, background, finisher, stopper, platformOps, platformActor, agentDocs,
57
58
  /** The schedule tools read tasks and grants; their writes go through the task service. */
58
59
  scheduleStore,
59
60
  /** `ScheduleUpdate`'s write: its field change and grant changes in one transaction. */
@@ -67,6 +68,10 @@ let BuiltinTools = class BuiltinTools {
67
68
  devices,
68
69
  background,
69
70
  tasks: { finisher, stopper },
71
+ subagents: {
72
+ inTree: async (root, id) => id !== root && (await conversationAncestors(db.db, id)).includes(root),
73
+ childrenOf: (orgId, conversationId) => readChildAgents(db.db, orgId, conversationId),
74
+ },
70
75
  attachments,
71
76
  storage,
72
77
  eventLog,
@@ -103,7 +108,7 @@ let BuiltinTools = class BuiltinTools {
103
108
  points,
104
109
  config,
105
110
  cache: webPages,
106
- extract: (ctx, page, prompt) => extractAnswer({ purposes, eventLog, stepLog, config, log, hooks: host?.hooks, usageReport }, ctx, page, prompt),
111
+ extract: (ctx, page, prompt) => extractAnswer({ purposes, eventLog, stepLog, config, log, hooks: host?.hooks }, ctx, page, prompt),
107
112
  }),
108
113
  // the platform's own operations and docs, as the run's person (Platform tool spec)
109
114
  platformTool({
@@ -149,19 +154,18 @@ BuiltinTools = __decorate([
149
154
  __param(9, Inject(WebPages)),
150
155
  __param(10, Inject(ModelPurposesService)),
151
156
  __param(11, Inject(ExtensionHost)),
152
- __param(12, Inject(UsageReporter)),
153
- __param(13, Inject(StepLog)),
154
- __param(14, Inject(KERNEL_LOGGER)),
155
- __param(15, Inject(BackgroundTaskStore)),
156
- __param(16, Inject(BackgroundTaskFinisher)),
157
- __param(17, Inject(BackgroundTaskStopper)),
158
- __param(18, Inject(PlatformOperations)),
159
- __param(19, Inject(PlatformActor)),
160
- __param(20, Inject(AgentDocs)),
161
- __param(21, Inject(ScheduledTaskStore)),
162
- __param(22, Inject(ScheduleUpdates)),
163
- __param(23, Inject(ScheduleToolsPort)),
164
- __param(24, Optional()),
165
- __param(24, Inject(RUN_CONTEXT_CLOCK))
157
+ __param(12, Inject(StepLog)),
158
+ __param(13, Inject(KERNEL_LOGGER)),
159
+ __param(14, Inject(BackgroundTaskStore)),
160
+ __param(15, Inject(BackgroundTaskFinisher)),
161
+ __param(16, Inject(BackgroundTaskStopper)),
162
+ __param(17, Inject(PlatformOperations)),
163
+ __param(18, Inject(PlatformActor)),
164
+ __param(19, Inject(AgentDocs)),
165
+ __param(20, Inject(ScheduledTaskStore)),
166
+ __param(21, Inject(ScheduleUpdates)),
167
+ __param(22, Inject(ScheduleToolsPort)),
168
+ __param(23, Optional()),
169
+ __param(23, Inject(RUN_CONTEXT_CLOCK))
166
170
  ], BuiltinTools);
167
171
  export { BuiltinTools };
@@ -29,19 +29,25 @@ const SPEC = {
29
29
  "Deliver. Other sub-agents of this conversation may run commands in this sandbox at " +
30
30
  "the same time. Always pass description: a few words saying what the command is for; the " +
31
31
  "user sees it instead of the command.\n\n" +
32
+ "Processes a normal call leaves running (started with '&' or nohup) may be stopped when the " +
33
+ "call ends, depending on the device, so use run_in_background for a dev server, a watcher or " +
34
+ "anything that must keep running after the call.\n\n" +
32
35
  "You can use the run_in_background parameter to run the command in the background, which " +
33
36
  "allows you to continue working while the command runs, e.g. a dev server, a long build or a " +
34
37
  "test suite. The call returns at once with a task id and the command's output goes to a file " +
35
38
  "under .capybara/tasks in the workspace directory. Read the output with TaskOutput (or Read) and stop the " +
36
- "task with TaskStop; you will be told when it finishes. You do not need to use '&' at the end " +
39
+ "task with TaskStop; you will be told when it finishes. TaskList lists this conversation's " +
40
+ "background tasks and their ids, running ones first. You do not need to use '&' at the end " +
37
41
  "of the command when using this parameter. In the background, timeout defaults to the " +
38
42
  "deployment's background maximum (7200000 by default). A background task ends when its " +
39
43
  "command exits, and processes it left running are stopped. A background task is lost if the " +
40
44
  "sandbox is suspended (it is suspended after it has been running for a while, " +
41
45
  "sandbox.limits.maxRunningMinutes), so keep its results in files under the workspace directory.\n\n" +
42
46
  "Network access goes through a proxy set in HTTP_PROXY / HTTPS_PROXY / ALL_PROXY; a tool " +
43
- "that ignores them fails with 'Operation not permitted'. A blocked domain is reported after " +
44
- "the output.",
47
+ "that ignores them fails with 'Operation not permitted' or cannot resolve names. Such tools, " +
48
+ "browsers for example, need the proxy passed explicitly: for Chromium (also headless, as " +
49
+ "Playwright or Puppeteer launch it) pass --proxy-server=$HTTPS_PROXY. A blocked domain is " +
50
+ "reported after the output.",
45
51
  inputSchema: {
46
52
  type: "object",
47
53
  properties: {
@@ -3,6 +3,7 @@ import type { BackgroundTaskFinisher } from "../../../background/finish.js";
3
3
  import type { BackgroundTaskStopper } from "../../../background/stop.js";
4
4
  import type { BackgroundTaskStore } from "../../../background/store.js";
5
5
  import type { KernelConfig } from "../../../config/schema.js";
6
+ import type { ChildAgent } from "../../../conversations/agent-tree.js";
6
7
  import type { AttachmentsService } from "../../../conversations/attachments.service.js";
7
8
  import type { EventLog } from "../../../conversations/event-log.js";
8
9
  import { type ConversationDevices } from "../../../devices/conversation-devices.js";
@@ -25,7 +26,16 @@ export interface SandboxToolDeps {
25
26
  */
26
27
  devices: Pick<ConversationDevices, "forTool"> & Partial<Pick<ConversationDevices, "usableNow" | "sandboxLevel">>;
27
28
  /** Background `Bash` tasks; absent in test stubs, where `run_in_background` is refused. */
28
- background?: Pick<BackgroundTaskStore, "reserve" | "markStarted" | "failLaunch" | "finishStoppedLaunch" | "releaseStop" | "get" | "advanceOffset">;
29
+ background?: Pick<BackgroundTaskStore, "reserve" | "markStarted" | "failLaunch" | "finishStoppedLaunch" | "releaseStop" | "get" | "advanceOffset" | "runningOwnedBy" | "finishedOwnedBy">;
30
+ /**
31
+ * Whether `id` is a sub-agent conversation in the tree under `rootConversationId` (TaskOutput /
32
+ * TaskStop tell a sub-agent's agentId apart from an unknown task id), and the sub-agents a
33
+ * conversation dispatched itself (`TaskList`); absent in test stubs.
34
+ */
35
+ subagents?: {
36
+ inTree(rootConversationId: string, id: string): Promise<boolean>;
37
+ childrenOf(orgId: string, conversationId: string): Promise<ChildAgent[]>;
38
+ };
29
39
  /**
30
40
  * What `TaskOutput` and `TaskStop` finish and stop tasks with; absent in test stubs, where both
31
41
  * answer that background tasks are not available.
@@ -83,6 +93,13 @@ export declare function noSandboxError(): ToolError;
83
93
  export declare const SANDBOX_UNREACHABLE_TEXT = "The sandbox provider can't be reached (the connection failed), so this call did nothing in the sandbox; retrying won't help until a super admin checks the sandbox extension's configuration (Admin console \u2192 Extensions). Continue without the sandbox, or ask the person to have a super admin check it.";
84
94
  /** A provider connection that broke during the call: the provider may have acted before it broke. */
85
95
  export declare const SANDBOX_CONNECTION_DROPPED_TEXT = "The connection to the sandbox provider broke during this call, so it may or may not have taken effect; check the sandbox state before retrying. If it fails again, continue without the sandbox and ask the person to have a super admin check the sandbox extension's configuration (Admin console \u2192 Extensions).";
96
+ /**
97
+ * A cloud provider refused the device's tier (`sandbox.tier_refused`, spec §5.3): the tier the
98
+ * device asks for, never the provider's own message (it may name its settings).
99
+ */
100
+ export declare const sandboxTierRefusedText: (tier: string) => string;
101
+ /** A cloud provider failed to create the device's sandbox otherwise (`sandbox.create_failed`). */
102
+ export declare const SANDBOX_CREATE_FAILED_TEXT = "The cloud sandbox provider could not create this device's sandbox, so nothing ran in it. Retry once; if it fails again, continue without the sandbox and ask the person to have a super admin check the sandbox extension's settings (Admin console \u2192 Extensions).";
86
103
  /** The directory of attachments in the device (each conversation has a subdirectory). */
87
104
  export declare const attachmentsRoot: (roots: SandboxRoots) => string;
88
105
  /** {@link attachmentsRoot} of an instance with the default roots. */
@@ -1,4 +1,4 @@
1
- import { DEFAULT_SANDBOX_ROOTS, DeviceProtocolError, isFileSystemGoneError, isSandboxGoneError, ToolError, validateSandboxPath, validateSandboxPathShape, } from "@capybara-hq/plugin-sdk";
1
+ import { DEFAULT_SANDBOX_ROOTS, DeviceProtocolError, isFileSystemGoneError, isSandboxGoneError, isSandboxTier, ToolError, validateSandboxPath, validateSandboxPathShape, } from "@capybara-hq/plugin-sdk";
2
2
  import { ANONYMOUS_NO_DEVICE, } from "../../../devices/conversation-devices.js";
3
3
  import { ApiError } from "../../../errors.js";
4
4
  import { UNSANDBOXED_NOT_ALLOWED_ERROR } from "../../../local-devices/local-device-provider.js";
@@ -48,6 +48,13 @@ const DEVICE_OFFLINE_TEXT = "The device's machine is offline. Ask the person to
48
48
  const DEVICE_OUTDATED_TEXT = "The device's machine runs an outdated capybara-device. Ask the person to update it on that machine and start it again.";
49
49
  const DEVICE_REVOKED_TEXT = "The device's machine was disconnected. Ask the person to run capybara-device logout, then capybara-device login on it, or to start a new conversation on another device.";
50
50
  const deviceProtocolText = (detail) => `The device's machine sent an answer the platform cannot read (${detail}). Ask the person to update capybara-device on that machine, then retry.`;
51
+ /**
52
+ * A cloud provider refused the device's tier (`sandbox.tier_refused`, spec §5.3): the tier the
53
+ * device asks for, never the provider's own message (it may name its settings).
54
+ */
55
+ export const sandboxTierRefusedText = (tier) => `The cloud sandbox can't run this device at the ${tier} tier: the sandbox provider refused to create it there, so nothing ran in the sandbox and retrying won't help. Ask the person to lower the device's sandbox tier on its device page, or to have an org admin lower the org's highest tier in the sandbox settings, or a super admin to allow that tier in the sandbox extension's settings (Admin console → Extensions). Continue without the sandbox meanwhile.`;
56
+ /** A cloud provider failed to create the device's sandbox otherwise (`sandbox.create_failed`). */
57
+ export const SANDBOX_CREATE_FAILED_TEXT = "The cloud sandbox provider could not create this device's sandbox, so nothing ran in it. Retry once; if it fails again, continue without the sandbox and ask the person to have a super admin check the sandbox extension's settings (Admin console → Extensions).";
51
58
  const LOCK_LOST_TEXT = "The sandbox operation was interrupted because the sandbox lock was lost; check the sandbox state and retry.";
52
59
  /** The directory of attachments in the device (each conversation has a subdirectory). */
53
60
  export const attachmentsRoot = (roots) => `${roots.workspace}/attachments`;
@@ -357,6 +364,12 @@ export function mapSandboxError(e, log) {
357
364
  return new ToolError(UNSANDBOXED_TEXT);
358
365
  if (e.code === "device.tier_not_granted")
359
366
  return new ToolError(UNATTENDED_OPEN_TIER_ERROR);
367
+ if (e.code === "sandbox.tier_refused") {
368
+ const tier = detail?.tier;
369
+ return new ToolError(sandboxTierRefusedText(isSandboxTier(tier) ? tier : "requested"));
370
+ }
371
+ if (e.code === "sandbox.create_failed")
372
+ return new ToolError(SANDBOX_CREATE_FAILED_TEXT);
360
373
  }
361
374
  // an operation outside withSandbox's own mapping (it records lost files itself)
362
375
  if (isFileSystemGoneError(e))
@@ -11,6 +11,7 @@ export { compileGlob, GlobPatternError, MAX_GLOB_STARS } from "./glob-match.js";
11
11
  * a provider for it. Allowed by default; with the org setting `sandboxToolPolicy` set to ask,
12
12
  * every one but Read / Glob / Grep needs approval (see policy.ts).
13
13
  * `TaskOutput` and `TaskStop` read and stop background `Bash` tasks through
14
- * `SandboxService.ifRunning` (never creating or resuming a sandbox); always allowed.
14
+ * `SandboxService.ifRunning` (never creating or resuming a sandbox); `TaskList` lists them and the
15
+ * conversation's sub-agents from PG; all three always allowed.
15
16
  */
16
17
  export declare function sandboxTools(deps: SandboxToolDeps): BuiltinTool[];
@@ -4,6 +4,7 @@ import { sandboxEditTool } from "./edit.js";
4
4
  import { sandboxGlobTool } from "./glob.js";
5
5
  import { sandboxGrepTool } from "./grep.js";
6
6
  import { sandboxReadTool } from "./read.js";
7
+ import { taskListTool } from "./task-list.js";
7
8
  import { taskOutputTool } from "./task-output.js";
8
9
  import { taskStopTool } from "./task-stop.js";
9
10
  import { sandboxWriteTool } from "./write.js";
@@ -18,7 +19,8 @@ export { compileGlob, GlobPatternError, MAX_GLOB_STARS } from "./glob-match.js";
18
19
  * a provider for it. Allowed by default; with the org setting `sandboxToolPolicy` set to ask,
19
20
  * every one but Read / Glob / Grep needs approval (see policy.ts).
20
21
  * `TaskOutput` and `TaskStop` read and stop background `Bash` tasks through
21
- * `SandboxService.ifRunning` (never creating or resuming a sandbox); always allowed.
22
+ * `SandboxService.ifRunning` (never creating or resuming a sandbox); `TaskList` lists them and the
23
+ * conversation's sub-agents from PG; all three always allowed.
22
24
  */
23
25
  export function sandboxTools(deps) {
24
26
  return [
@@ -31,5 +33,6 @@ export function sandboxTools(deps) {
31
33
  sandboxDeliverTool(deps),
32
34
  taskOutputTool(deps),
33
35
  taskStopTool(deps),
36
+ taskListTool(deps),
34
37
  ];
35
38
  }
@@ -0,0 +1,12 @@
1
+ import type { BuiltinTool } from "../../registry.js";
2
+ import { type SandboxToolDeps } from "./common.js";
3
+ /** How many finished background tasks (and finished sub-agents) `TaskList` lists at most. */
4
+ export declare const TASK_LIST_FINISHED_LIMIT = 20;
5
+ /**
6
+ * Built-in `TaskList`: the calling conversation's own background tasks (never its sub-agents' or
7
+ * another conversation's: owner `conversation_id`, as `TaskOutput` checks) and the sub-agents it
8
+ * dispatched itself. Running entries first (oldest first), then with `status: "all"` the
9
+ * {@link TASK_LIST_FINISHED_LIMIT} most recently finished. Reads PG only: it never checks a task in
10
+ * its sandbox, so a status is the poller's or a tool's last one.
11
+ */
12
+ export declare function taskListTool(deps: SandboxToolDeps): BuiltinTool;