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

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 (242) hide show
  1. package/dist/agents/admin-agents.d.ts +16 -3
  2. package/dist/agents/admin-agents.js +65 -7
  3. package/dist/agents/agents.schemas.d.ts +24 -6
  4. package/dist/agents/agents.service.d.ts +4 -3
  5. package/dist/agents/agents.service.js +39 -26
  6. package/dist/agents/definition.d.ts +44 -6
  7. package/dist/agents/definition.js +86 -18
  8. package/dist/agents/from-template.d.ts +6 -3
  9. package/dist/agents/from-template.js +57 -44
  10. package/dist/agents/org-templates.js +97 -41
  11. package/dist/agents/templates.d.ts +6 -0
  12. package/dist/agents/templates.js +15 -1
  13. package/dist/catalog/admin-catalog.controller.d.ts +2 -4
  14. package/dist/catalog/admin-catalog.controller.js +2 -6
  15. package/dist/catalog/catalog.module.js +3 -0
  16. package/dist/catalog/claude/report.d.ts +9 -2
  17. package/dist/catalog/claude/report.js +1 -0
  18. package/dist/catalog/claude/translate.js +1 -1
  19. package/dist/catalog/component-promotion.js +1 -2
  20. package/dist/catalog/component-state.d.ts +13 -1
  21. package/dist/catalog/component-state.js +14 -5
  22. package/dist/catalog/marketplaces.service.d.ts +1 -1
  23. package/dist/catalog/marketplaces.service.js +2 -1
  24. package/dist/catalog/org-catalog.controller.d.ts +13 -3
  25. package/dist/catalog/org-catalog.controller.js +26 -4
  26. package/dist/catalog/org-catalog.schemas.d.ts +13 -0
  27. package/dist/catalog/org-catalog.schemas.js +34 -0
  28. package/dist/catalog/org-plugin-uploads.controller.js +0 -1
  29. package/dist/catalog/org-plugin-uploads.d.ts +0 -1
  30. package/dist/catalog/org-plugin-uploads.js +0 -3
  31. package/dist/catalog/org-plugin-uploads.schemas.d.ts +0 -1
  32. package/dist/catalog/org-plugin-uploads.schemas.js +0 -2
  33. package/dist/catalog/platform-components.d.ts +0 -1
  34. package/dist/catalog/platform-components.js +3 -8
  35. package/dist/catalog/plugin-import.d.ts +0 -8
  36. package/dist/catalog/plugin-import.js +4 -35
  37. package/dist/catalog/plugin-install.d.ts +2 -2
  38. package/dist/catalog/plugin-install.js +2 -2
  39. package/dist/catalog/plugin-package.d.ts +7 -0
  40. package/dist/catalog/plugin-package.js +27 -1
  41. package/dist/catalog/plugin-upgrade.d.ts +5 -6
  42. package/dist/catalog/plugin-upgrade.js +5 -23
  43. package/dist/catalog/requests.service.d.ts +66 -10
  44. package/dist/catalog/requests.service.js +196 -15
  45. package/dist/channels/actions.d.ts +2 -0
  46. package/dist/channels/actions.js +19 -4
  47. package/dist/channels/cards.d.ts +16 -2
  48. package/dist/channels/cards.js +40 -7
  49. package/dist/channels/channels.module.js +3 -0
  50. package/dist/channels/outbound.d.ts +22 -1
  51. package/dist/channels/outbound.js +116 -7
  52. package/dist/channels/phrases.d.ts +25 -0
  53. package/dist/channels/phrases.js +19 -0
  54. package/dist/channels/threads.d.ts +12 -0
  55. package/dist/channels/threads.js +34 -0
  56. package/dist/config/schema.d.ts +23 -1
  57. package/dist/config/schema.js +105 -5
  58. package/dist/conversations/conversations.service.d.ts +42 -9
  59. package/dist/conversations/conversations.service.js +57 -25
  60. package/dist/conversations/events.d.ts +106 -11
  61. package/dist/conversations/events.js +121 -18
  62. package/dist/conversations/message-context.d.ts +6 -3
  63. package/dist/conversations/message-context.js +14 -10
  64. package/dist/conversations/queue.d.ts +15 -2
  65. package/dist/conversations/queue.js +22 -3
  66. package/dist/conversations/queue.service.d.ts +12 -6
  67. package/dist/conversations/queue.service.js +36 -13
  68. package/dist/db/kernel-schema.d.ts +105 -3
  69. package/dist/devices/conversation-devices.d.ts +8 -1
  70. package/dist/devices/conversation-devices.js +8 -0
  71. package/dist/devices/devices.controller.d.ts +21 -4
  72. package/dist/devices/devices.controller.js +46 -8
  73. package/dist/devices/devices.schemas.d.ts +9 -1
  74. package/dist/devices/devices.schemas.js +11 -3
  75. package/dist/devices/devices.service.d.ts +176 -4
  76. package/dist/devices/devices.service.js +341 -6
  77. package/dist/devices/dto.d.ts +56 -3
  78. package/dist/devices/dto.js +51 -1
  79. package/dist/devices/public-suffix.d.ts +6 -0
  80. package/dist/devices/public-suffix.js +79 -0
  81. package/dist/errors.d.ts +46 -5
  82. package/dist/errors.js +46 -5
  83. package/dist/evals/reconstruct.d.ts +18 -13
  84. package/dist/evals/reconstruct.js +50 -36
  85. package/dist/evals/recorded-tools.d.ts +7 -7
  86. package/dist/evals/recorded-tools.js +4 -3
  87. package/dist/evals/trajectory.d.ts +6 -1
  88. package/dist/evals/trajectory.js +7 -0
  89. package/dist/extensions/package.js +2 -2
  90. package/dist/http/api.module.js +5 -0
  91. package/dist/inbox/inbox.module.js +2 -1
  92. package/dist/inbox/inbox.service.d.ts +19 -4
  93. package/dist/inbox/inbox.service.js +14 -3
  94. package/dist/infra/config/kernel-config.service.js +11 -0
  95. package/dist/infra/events/kernel-events.d.ts +2 -1
  96. package/dist/local-devices/device-policy.service.d.ts +65 -0
  97. package/dist/local-devices/device-policy.service.js +217 -0
  98. package/dist/local-devices/local-device-gateway.js +4 -1
  99. package/dist/local-devices/local-device-provider.d.ts +40 -3
  100. package/dist/local-devices/local-device-provider.js +109 -7
  101. package/dist/local-devices/local-devices.module.d.ts +2 -1
  102. package/dist/local-devices/local-devices.module.js +19 -3
  103. package/dist/local-devices/machines.d.ts +14 -3
  104. package/dist/local-devices/machines.js +41 -3
  105. package/dist/local-devices/network-grants.d.ts +104 -0
  106. package/dist/local-devices/network-grants.js +288 -0
  107. package/dist/local-devices/policy-summary.d.ts +20 -0
  108. package/dist/local-devices/policy-summary.js +63 -0
  109. package/dist/orgs/orgs.module.js +4 -10
  110. package/dist/orgs/roles.d.ts +1 -1
  111. package/dist/orgs/roles.js +4 -0
  112. package/dist/orgs/settings.controller.js +2 -1
  113. package/dist/orgs/settings.service.d.ts +164 -12
  114. package/dist/orgs/settings.service.js +212 -24
  115. package/dist/platform/exclusions.js +11 -1
  116. package/dist/platform/operation.js +4 -0
  117. package/dist/platform/ops/admin-items.ops.js +1 -1
  118. package/dist/platform/ops/agent-skills.ops.js +2 -2
  119. package/dist/platform/ops/agent-templates.ops.js +2 -2
  120. package/dist/platform/ops/agents.ops.js +11 -15
  121. package/dist/platform/ops/devices.ops.js +3 -1
  122. package/dist/platform/ops/inbox.ops.js +19 -0
  123. package/dist/platform/ops/org-settings.ops.js +14 -5
  124. package/dist/platform/ops/platform.ops.d.ts +9 -1
  125. package/dist/platform/ops/platform.ops.js +34 -12
  126. package/dist/platform/ops/requests.ops.js +3 -2
  127. package/dist/platform/ops/schedules.ops.d.ts +21 -0
  128. package/dist/platform/ops/schedules.ops.js +470 -0
  129. package/dist/platform/ops/skills.ops.js +3 -3
  130. package/dist/platform/platform-ops.module.d.ts +2 -1
  131. package/dist/platform/platform-ops.module.js +5 -0
  132. package/dist/platform/route-schemas.js +3 -0
  133. package/dist/roles/worker.module.js +3 -0
  134. package/dist/runtime/context/build.js +13 -4
  135. package/dist/runtime/context/compaction.js +6 -3
  136. package/dist/runtime/context/device-paths.d.ts +43 -21
  137. package/dist/runtime/context/device-paths.js +104 -21
  138. package/dist/runtime/context/run-context.d.ts +9 -0
  139. package/dist/runtime/context/run-context.js +8 -0
  140. package/dist/runtime/context/skills.d.ts +14 -1
  141. package/dist/runtime/context/skills.js +36 -5
  142. package/dist/runtime/maintenance.d.ts +4 -2
  143. package/dist/runtime/maintenance.js +16 -5
  144. package/dist/runtime/run-finish.d.ts +6 -1
  145. package/dist/runtime/run-finish.js +16 -2
  146. package/dist/runtime/run-queue.js +21 -2
  147. package/dist/runtime/run-worker.js +14 -33
  148. package/dist/runtime/runtime.module.js +3 -0
  149. package/dist/runtime/subagents/definition.d.ts +32 -14
  150. package/dist/runtime/subagents/definition.js +106 -109
  151. package/dist/runtime/subagents/dispatch.js +4 -3
  152. package/dist/runtime/subagents/preamble.d.ts +2 -1
  153. package/dist/runtime/subagents/preamble.js +2 -1
  154. package/dist/runtime/waits.js +14 -4
  155. package/dist/sandbox/sandbox.service.d.ts +120 -10
  156. package/dist/sandbox/sandbox.service.js +335 -28
  157. package/dist/sandbox/tiers.d.ts +86 -0
  158. package/dist/sandbox/tiers.js +96 -0
  159. package/dist/schedules/effective-settings.d.ts +16 -0
  160. package/dist/schedules/effective-settings.js +17 -0
  161. package/dist/schedules/errors.d.ts +8 -0
  162. package/dist/schedules/errors.js +8 -0
  163. package/dist/schedules/fire.d.ts +118 -0
  164. package/dist/schedules/fire.js +625 -0
  165. package/dist/schedules/grant-rules.d.ts +94 -0
  166. package/dist/schedules/grant-rules.js +126 -0
  167. package/dist/schedules/job-ids.d.ts +32 -0
  168. package/dist/schedules/job-ids.js +27 -0
  169. package/dist/schedules/pause.d.ts +9 -0
  170. package/dist/schedules/pause.js +33 -0
  171. package/dist/schedules/run-tracker.d.ts +81 -0
  172. package/dist/schedules/run-tracker.js +333 -0
  173. package/dist/schedules/scan.job.d.ts +64 -0
  174. package/dist/schedules/scan.job.js +303 -0
  175. package/dist/schedules/schedule-math.d.ts +31 -0
  176. package/dist/schedules/schedule-math.js +223 -0
  177. package/dist/schedules/scheduled-tasks.service.d.ts +351 -0
  178. package/dist/schedules/scheduled-tasks.service.js +1193 -0
  179. package/dist/schedules/schedules.controller.d.ts +68 -0
  180. package/dist/schedules/schedules.controller.js +242 -0
  181. package/dist/schedules/schedules.module.d.ts +16 -0
  182. package/dist/schedules/schedules.module.js +65 -0
  183. package/dist/schedules/schedules.schemas.d.ts +316 -0
  184. package/dist/schedules/schedules.schemas.js +186 -0
  185. package/dist/schedules/store.d.ts +81 -0
  186. package/dist/schedules/store.js +390 -0
  187. package/dist/schedules/store.module.d.ts +6 -0
  188. package/dist/schedules/store.module.js +21 -0
  189. package/dist/schedules/types.d.ts +108 -0
  190. package/dist/schedules/types.js +1 -0
  191. package/dist/schedules/unattended.d.ts +117 -0
  192. package/dist/schedules/unattended.js +228 -0
  193. package/dist/setup/oauth-token-probe.js +8 -4
  194. package/dist/skills/agent-skills.service.d.ts +4 -8
  195. package/dist/skills/agent-skills.service.js +18 -53
  196. package/dist/skills/catalog.d.ts +65 -62
  197. package/dist/skills/catalog.js +109 -206
  198. package/dist/skills/conversation-catalog.d.ts +3 -3
  199. package/dist/skills/conversation-catalog.js +5 -12
  200. package/dist/skills/invoke.d.ts +2 -2
  201. package/dist/skills/skills.controller.d.ts +3 -1
  202. package/dist/skills/skills.service.d.ts +38 -37
  203. package/dist/skills/skills.service.js +168 -107
  204. package/dist/skills/usable.d.ts +57 -8
  205. package/dist/skills/usable.js +172 -38
  206. package/dist/tools/approvals.controller.d.ts +4 -2
  207. package/dist/tools/approvals.controller.js +17 -2
  208. package/dist/tools/approvals.schemas.d.ts +1 -0
  209. package/dist/tools/approvals.schemas.js +3 -1
  210. package/dist/tools/approvals.service.d.ts +182 -7
  211. package/dist/tools/approvals.service.js +597 -13
  212. package/dist/tools/builtin-names.d.ts +25 -4
  213. package/dist/tools/builtin-names.js +45 -4
  214. package/dist/tools/builtins/builtin-tools.d.ts +8 -0
  215. package/dist/tools/builtins/builtin-tools.js +23 -2
  216. package/dist/tools/builtins/sandbox/bash.js +16 -7
  217. package/dist/tools/builtins/sandbox/common.d.ts +1 -1
  218. package/dist/tools/builtins/sandbox/common.js +33 -10
  219. package/dist/tools/builtins/sandbox/edit.js +7 -3
  220. package/dist/tools/builtins/sandbox/file-state.d.ts +31 -1
  221. package/dist/tools/builtins/sandbox/file-state.js +33 -3
  222. package/dist/tools/builtins/sandbox/write.js +8 -4
  223. package/dist/tools/builtins/schedules.d.ts +107 -0
  224. package/dist/tools/builtins/schedules.js +789 -0
  225. package/dist/tools/elicitation.d.ts +2 -0
  226. package/dist/tools/elicitation.js +1 -1
  227. package/dist/tools/fixed-ask.d.ts +7 -0
  228. package/dist/tools/fixed-ask.js +9 -0
  229. package/dist/tools/network-asks.d.ts +109 -0
  230. package/dist/tools/network-asks.js +221 -0
  231. package/dist/tools/pipeline.d.ts +53 -6
  232. package/dist/tools/pipeline.js +202 -13
  233. package/dist/tools/policy.d.ts +21 -8
  234. package/dist/tools/policy.js +63 -9
  235. package/dist/tools/registry.d.ts +10 -1
  236. package/dist/tools/tools.module.js +12 -0
  237. package/package.json +2 -2
  238. package/src/migrations/0113_scheduled_tasks.sql +108 -0
  239. package/src/migrations/0114_network_asks.sql +23 -0
  240. package/src/migrations/0115_network_requests.sql +28 -0
  241. package/src/migrations/0116_skills_default_on.sql +37 -0
  242. package/src/migrations/0117_sandbox_tiers.sql +11 -0
@@ -23,7 +23,7 @@ import { TransactionHost } from "../infra/database/transaction-host.js";
23
23
  import { Transactional } from "../infra/database/transactional.decorator.js";
24
24
  import { KernelEvents } from "../infra/events/kernel-events.js";
25
25
  import { KERNEL_BUS, KERNEL_LOGGER } from "../infra/tokens.js";
26
- import { pinnedFailureText, SkillsCatalogService } from "../skills/catalog.js";
26
+ import { SkillsCatalogService } from "../skills/catalog.js";
27
27
  import { normalizeStoredDefinitionIn } from "../tools/legacy-data.js";
28
28
  import { ToolPipeline } from "../tools/pipeline.js";
29
29
  import { RunAbort } from "./abort.js";
@@ -597,37 +597,13 @@ let RunWorker = class RunWorker {
597
597
  await this.eventLog.notify(conversationId, toSeq);
598
598
  }
599
599
  // 技能目录快照(Ruling M17):在置为 running 之前写,崩溃重试时仍走这里(幂等键去重)
600
- try {
601
- await this.skillsCatalog.record({
602
- orgId: conv.org_id,
603
- agentId: conv.agent_id,
604
- conversationId,
605
- runId,
606
- agent,
607
- }, { log: this.log });
608
- }
609
- catch (e) {
610
- // Pinned skill bodies could not be read (Decision 9), or the pinned skills kept changing
611
- // while they were read (`conflict`): fail before any model request. A transient failure
612
- // or a conflict is fixed by sending again; a permanent one names the skill for the owner
613
- // (`SkillsCatalogService.record` already logged it at error). Other errors take the generic path.
614
- if (!(e instanceof ApiError) ||
615
- (e.code !== "storage.unavailable" && e.code !== "conflict")) {
616
- throw e;
617
- }
618
- this.log.warn("skills catalog not recorded at run start", {
619
- conversationId,
620
- runId,
621
- code: e.code,
622
- err: e,
623
- });
624
- const message = e.code === "conflict" ? e.message : pinnedFailureText(e);
625
- await this.finish(conversationId, runId, "failed", null, {
626
- type: "run_failed",
627
- payload: { error: { code: e.code, message } },
628
- });
629
- return "finished";
630
- }
600
+ await this.skillsCatalog.record({
601
+ orgId: conv.org_id,
602
+ agentId: conv.agent_id,
603
+ conversationId,
604
+ runId,
605
+ agent,
606
+ }, { log: this.log });
631
607
  // run context (spec §5): after the catalog, before the run is running, so before any
632
608
  // compaction and model call; a retried run start finds its event or no change
633
609
  await this.runContext.record({
@@ -861,7 +837,7 @@ let RunWorker = class RunWorker {
861
837
  // delivery (agent map spec §5.3), not a message
862
838
  const boundary = await t
863
839
  .selectFrom("conversation_events")
864
- .select("type")
840
+ .select(["type", "payload"])
865
841
  .where("conversation_id", "=", conversationId)
866
842
  .where("seq", "=", run.trigger_seq)
867
843
  .executeTakeFirst();
@@ -882,6 +858,11 @@ let RunWorker = class RunWorker {
882
858
  trigger: "subagent",
883
859
  triggerSeq: Number(run.trigger_seq),
884
860
  }),
861
+ // a scheduled task's message (scheduled tasks spec §6); display only
862
+ ...(boundary?.type === "user_message" &&
863
+ boundary.payload.schedule !== undefined && {
864
+ trigger: "schedule",
865
+ }),
885
866
  },
886
867
  },
887
868
  ]);
@@ -16,6 +16,7 @@ import { IdentityModule } from "../identity/identity.module.js";
16
16
  import { LockService } from "../infra/lock/lock.service.js";
17
17
  import { QueueModule } from "../infra/queue/queue.module.js";
18
18
  import { REDIS } from "../infra/tokens.js";
19
+ import { ScheduledTaskTrackerModule } from "../schedules/run-tracker.js";
19
20
  import { SkillsModule } from "../skills/skills.module.js";
20
21
  import { ToolsModule } from "../tools/tools.module.js";
21
22
  import { RunAbort } from "./abort.js";
@@ -64,6 +65,8 @@ RuntimeModule = __decorate([
64
65
  TitlesModule,
65
66
  StepLogModule,
66
67
  BackgroundModule,
68
+ // a scheduled task's run follows its kernel run's end (`RunFinish`)
69
+ ScheduledTaskTrackerModule,
67
70
  // the producer side of `wait-timeout` jobs (`MaintenanceProcessor` consumes them)
68
71
  QueueModule.registerQueue(MAINTENANCE_QUEUE_NAME),
69
72
  ],
@@ -1,6 +1,6 @@
1
1
  import { type AgentTemplateTier } from "@capybara-hq/plugin-sdk";
2
- import { type AgentDefinition, type DisabledToolRef, type ModelRef } from "../../agents/definition.js";
3
- import type { EventPayload } from "../../conversations/events.js";
2
+ import { type AgentDefinition, DisabledSkillRef, type DisabledToolRef, type ModelRef } from "../../agents/definition.js";
3
+ import { type EventPayload } from "../../conversations/events.js";
4
4
  import type { KernelSchemaDb } from "../../db/kernel-schema.js";
5
5
  import type { KernelConfigService } from "../../infra/config/kernel-config.service.js";
6
6
  import type { ModelPurposesService } from "../../models/purposes.js";
@@ -21,7 +21,15 @@ export interface EffectiveDefinition {
21
21
  definition: AgentDefinition;
22
22
  template: EventPayload<"subagent_started">["template"];
23
23
  maxSteps: number;
24
- /** Dispatch warnings (pinned skills dropped), recorded in `subagent_started.warnings`. */
24
+ /**
25
+ * The child's preamble, frozen into `subagent_started.preamble` (model-visible):
26
+ * {@link SUBAGENT_PREAMBLE}, plus the line naming the template's skills to load first.
27
+ */
28
+ preamble: string;
29
+ /**
30
+ * Dispatch warnings (a template skill the child does not have), recorded in
31
+ * `subagent_started.warnings`.
32
+ */
25
33
  warnings: string[];
26
34
  }
27
35
  export interface EffectiveDefinitionDeps {
@@ -38,6 +46,15 @@ type Policy = "ask" | "deny";
38
46
  * `allow`, which the policy check reads from the agent's current version) are skipped on both sides.
39
47
  */
40
48
  export declare function stricterPolicies(base: Record<string, string>, over: Record<string, string>): Record<string, Policy>;
49
+ /**
50
+ * A template's `disallowedSkills` as `disabledSkills` entries (skills default-on spec §6.1, §6.2):
51
+ * `<plugin>:*` turns the whole plugin off, `<plugin>:<name>` one of its skills, and a bare `<name>`
52
+ * the org's usable skills of that name without a plugin (by id). A bare name the org does not have
53
+ * and an entry that is no valid reference (stored template data is not re-validated) are dropped.
54
+ */
55
+ export declare function disallowedSkillRefs(db: KernelSchemaDb, orgId: string, refs: readonly unknown[] | undefined): Promise<DisabledSkillRef[]>;
56
+ /** The preamble line naming the skills a template child loads first (skills default-on §6.1). */
57
+ export declare const loadSkillsFirstText: (names: readonly string[]) => string;
41
58
  /** An org agent's version and definition as checked by its gates. */
42
59
  export interface CheckedOrgAgent {
43
60
  version: number;
@@ -53,9 +70,9 @@ export interface ChildDepth {
53
70
  /**
54
71
  * The effective definition of a sub-agent at its first dispatch (spec §5.3–§5.5):
55
72
  * - `general` / `inline` / `plugin`: the parent's definition narrowed by the template (tools by
56
- * resolved key, `disallowedTools`, {@link CHILD_REMOVED_TOOLS}; policies stricter-wins), the
57
- * template's instructions, pinned = the template's skills the parent selects (general pins
58
- * nothing), `maxSteps = min(template ?? runtime.maxSteps, runtime.maxSteps)`, and the model tier
73
+ * resolved key, `disallowedTools`, {@link CHILD_REMOVED_TOOLS}; policies stricter-wins; skills
74
+ * by its `disallowedSkills`), the template's instructions, its `skills` the child has named in
75
+ * the preamble to load first (general gets no line), `maxSteps = min(template ?? runtime.maxSteps, runtime.maxSteps)`, and the model tier
59
76
  * `tier` (the call's) → the template's → `inherit`; an unmapped tier runs on the parent's model
60
77
  * (`tierFallback`); a template `effort` is set when the resolved model declares it;
61
78
  * - `agent`: the org agent's version that passed the gates (`orgAgent`, from {@link checkOrgAgent}),
@@ -79,13 +96,16 @@ export declare function effectiveDefinition(d: EffectiveDefinitionDeps, a: Child
79
96
  }>;
80
97
  /**
81
98
  * What a follow-up (`resume`) may still use (final review I1, spec §5.3): the frozen definition's
82
- * turned-off tools together with the current version's (it can lose tools, never gain them), and
83
- * the frozen org skills intersected with the current ones. Recorded on the follow-up's task message
84
- * (`user_message.dispatch.narrowed`), so the run and its replay read it from the log.
99
+ * turned-off tools and skills together with the current version's (it can lose tools and skills,
100
+ * never gain them). Recorded on the follow-up's task message (`user_message.dispatch.narrowed`), so
101
+ * the run and its replay read it from the log.
85
102
  */
86
103
  export interface FollowUpNarrowing {
87
104
  /** Absent in logs from before tools were on by default (no tool narrowing then). */
88
105
  disabledTools?: DisabledToolRef[] | undefined;
106
+ /** Absent in logs from before skills were on by default (skills default-on spec §6.1). */
107
+ disabledSkills?: DisabledSkillRef[] | undefined;
108
+ /** Older logs only: the frozen org skills intersected with the current ones. */
89
109
  skills?: {
90
110
  orgSkills: string[];
91
111
  pinned?: string[] | undefined;
@@ -96,13 +116,11 @@ export interface FollowUpNarrowing {
96
116
  * definition) against `current`, the definition a fresh dispatch would read now: the dispatching
97
117
  * parent run's version for `general` / inline / plugin children, the dispatched org agent's
98
118
  * current version for an org agent child (whose tools are its own at dispatch too, §5.5). Its
99
- * `disabledTools` are both lists together; its `orgSkills` keep only those `current` still
100
- * selects; a pinned id that was one of the frozen org skills goes with it (the agent's own skills
101
- * stay).
119
+ * `disabledTools` and `disabledSkills` are both lists together.
102
120
  */
103
- export declare function narrowFollowUp(frozen: Pick<AgentDefinition, "disabledTools" | "skills">, current: Pick<AgentDefinition, "disabledTools" | "skills">): FollowUpNarrowing;
121
+ export declare function narrowFollowUp(frozen: Pick<AgentDefinition, "disabledTools" | "disabledSkills">, current: Pick<AgentDefinition, "disabledTools" | "disabledSkills">): FollowUpNarrowing;
104
122
  /**
105
123
  * The definition a child run uses: the frozen one with its trigger's follow-up narrowing. A
106
- * narrowing logged before tools were on by default (no `disabledTools`) narrows only skills.
124
+ * narrowing logged before tools (or skills) were on by default narrows nothing of that kind.
107
125
  */
108
126
  export declare function childRunDefinition(frozen: AgentDefinition, narrowed: FollowUpNarrowing | undefined): AgentDefinition;
@@ -1,10 +1,12 @@
1
- import { SKILL_ENTRY_FILE, sanitizeParams, } from "@capybara-hq/plugin-sdk";
2
- import { canonicalDisabledTools, } from "../../agents/definition.js";
1
+ import { sanitizeParams, } from "@capybara-hq/plugin-sdk";
2
+ import { canonicalDisabledSkills, canonicalDisabledTools, DisabledSkillRef, } from "../../agents/definition.js";
3
3
  import { loadTemplates } from "../../agents/templates.js";
4
+ import { SKILLS_CATALOG_MAX } from "../../conversations/events.js";
4
5
  import { ApiError } from "../../errors.js";
5
- import { PINNED_SKILLS_LIMITS } from "../../skills/catalog.js";
6
- import { selectedSkills } from "../../skills/usable.js";
6
+ import { invocationOf, resolveSkills } from "../../skills/catalog.js";
7
+ import { agentSkills, usableSkills } from "../../skills/usable.js";
7
8
  import { AGENT_TOOL, CHILD_REMOVED_TOOLS } from "../../tools/builtin-names.js";
9
+ import { SUBAGENT_PREAMBLE } from "./preamble.js";
8
10
  export { CHILD_REMOVED_TOOLS } from "../../tools/builtin-names.js";
9
11
  /**
10
12
  * The roster entry's template is gone (an inline template edited away, a plugin template
@@ -64,76 +66,81 @@ function childFilter(removeAgent, template, parent) {
64
66
  return { ...(allow !== undefined && { allow: [...allow] }), deny };
65
67
  }
66
68
  /**
67
- * The template's skills the parent selects (its `orgSkills` or the parent agent's own skills),
68
- * within the pinned limits (spec §5.3): inline templates name skill ids, plugin templates skill
69
- * names (`<name>` or `<plugin>:<name>`). A name that matches more than one selected skill picks, in
70
- * this order, the skill from the template's own plugin, the agent's own skill, the org skill (ties
71
- * by id), with a warning. Dropped ones get a warning.
69
+ * A template's `disallowedSkills` as `disabledSkills` entries (skills default-on spec §6.1, §6.2):
70
+ * `<plugin>:*` turns the whole plugin off, `<plugin>:<name>` one of its skills, and a bare `<name>`
71
+ * the org's usable skills of that name without a plugin (by id). A bare name the org does not have
72
+ * and an entry that is no valid reference (stored template data is not re-validated) are dropped.
72
73
  */
73
- async function pinnedFor(db, a, refs, byName,
74
- /** Further names the template lists (`selectedSkills`): resolved the same way, never pinned. */
75
- selected = []) {
76
- if (refs.length === 0 && selected.length === 0)
77
- return { pinned: [], warnings: [] };
78
- // org and agent skills, linked org copies and platform skills on in the org (phase 2), by id
79
- const rows = (await selectedSkills(db, {
80
- orgId: a.orgId,
81
- agentId: a.parentAgentId,
82
- orgSkills: a.parent.skills?.orgSkills ?? [],
83
- })).map((r) => ({
84
- id: r.id,
85
- name: r.name,
86
- scope: r.scope,
87
- plugin: r.plugin,
88
- bytes: r.manifest.files.find((f) => f.path === SKILL_ENTRY_FILE)?.size ?? 0,
89
- }));
90
- const pinned = [];
91
- const warnings = [];
92
- const own = byName?.plugin;
93
- const rank = (r) => own !== undefined && r.plugin === own ? 0 : r.scope === "agent" ? 1 : 2;
94
- const match = (ref) => {
95
- if (byName === null)
96
- return rows.find((r) => r.id === ref);
97
- const i = ref.indexOf(":");
98
- const found = i < 0
99
- ? rows.filter((r) => r.name === ref)
100
- : rows.filter((r) => r.name === ref.slice(i + 1) && r.plugin === ref.slice(0, i));
101
- // rows are ordered by id, and the sort is stable: ties keep that order
102
- const [first, ...rest] = found.sort((x, y) => rank(x) - rank(y));
103
- if (first && rest.length > 0) {
104
- const which = [`the one from the plugin ${own}`, "the agent's own skill", "the org skill"][rank(first)];
105
- warnings.push(`The skill name "${ref}" matches more than one selected skill; ${which} was pinned.`);
106
- }
107
- return first;
108
- };
109
- let total = 0;
110
- for (const ref of refs) {
111
- const r = match(ref);
112
- if (!r) {
113
- warnings.push(`The skill "${ref}" was not pinned: the agent does not select it.`);
114
- continue;
115
- }
116
- if (pinned.includes(r.id))
74
+ export async function disallowedSkillRefs(db, orgId, refs) {
75
+ const out = [];
76
+ const bare = new Set();
77
+ for (const ref of refs ?? []) {
78
+ if (typeof ref !== "string")
117
79
  continue;
118
- if (pinned.length >= PINNED_SKILLS_LIMITS.count) {
119
- warnings.push(`The skill "${r.name}" was not pinned: at most 3 skills can be pinned.`);
80
+ const i = ref.indexOf(":");
81
+ if (i < 0) {
82
+ bare.add(ref);
120
83
  continue;
121
84
  }
122
- if (total + r.bytes > PINNED_SKILLS_LIMITS.totalBytes) {
123
- warnings.push(`The skill "${r.name}" was not pinned: pinned skills are limited to 32 KB in total.`);
124
- continue;
85
+ const name = ref.slice(i + 1);
86
+ const entry = DisabledSkillRef.safeParse({
87
+ kind: "plugin",
88
+ plugin: ref.slice(0, i),
89
+ skills: name === "*" ? "all" : [name],
90
+ });
91
+ if (entry.success)
92
+ out.push(entry.data);
93
+ }
94
+ if (bare.size > 0) {
95
+ for (const s of await usableSkills(db, orgId)) {
96
+ if (s.plugin === null && bare.has(s.name))
97
+ out.push({ kind: "skill", skillId: s.id });
125
98
  }
126
- total += r.bytes;
127
- pinned.push(r.id);
128
99
  }
129
- for (const ref of selected) {
130
- if (refs.includes(ref))
131
- continue;
132
- if (!match(ref)) {
133
- warnings.push(`The skill "${ref}" is not available: the agent does not select it.`);
100
+ return out;
101
+ }
102
+ /** The warning of a template skill the child does not have. */
103
+ const skillNotLoadedText = (ref) => `The skill "${ref}" is not among the sub-agent's skills, so it is not asked to load it.`;
104
+ /** The preamble line naming the skills a template child loads first (skills default-on §6.1). */
105
+ export const loadSkillsFirstText = (names) => `Before you start, load these skills with Skill: ${names.join(", ")}.`;
106
+ /**
107
+ * The template's `skills` the child has (skills default-on spec §6.1: they are no longer pinned),
108
+ * by the names its catalog lists them under, in the template's order: the catalog its first run
109
+ * records (the agent `agentId` with the child's `disabledSkills`, model-invocable skills only).
110
+ * Inline templates name skill ids (`byId`; a platform skill's id names its linked copy too), plugin
111
+ * templates names (`<name>`, or `<plugin>:<name>` when the catalog's skill of that name is from
112
+ * that plugin). The others become warnings.
113
+ */
114
+ async function skillsToLoad(db, a, refs, byId) {
115
+ if (refs.length === 0)
116
+ return { names: [], warnings: [] };
117
+ const input = { orgId: a.orgId, agentId: a.agentId, disabledSkills: [...a.disabledSkills] };
118
+ const catalog = (await resolveSkills(db, { ...input, agent: input }))
119
+ .filter((r) => invocationOf(r.manifest).model)
120
+ .slice(0, SKILLS_CATALOG_MAX)
121
+ .map((r) => r.skill);
122
+ const rows = byId ? await agentSkills(db, input) : [];
123
+ const names = [];
124
+ const warnings = [];
125
+ for (const ref of refs) {
126
+ let found;
127
+ if (byId) {
128
+ const row = rows.find((r) => r.id === ref || r.platformSkillId === ref);
129
+ found = row && catalog.find((c) => c.id === row.id);
130
+ }
131
+ else {
132
+ const i = ref.indexOf(":");
133
+ found =
134
+ i < 0
135
+ ? catalog.find((c) => c.name === ref)
136
+ : catalog.find((c) => c.name === ref.slice(i + 1) && c.plugin === ref.slice(0, i));
134
137
  }
138
+ if (found === undefined)
139
+ warnings.push(skillNotLoadedText(ref));
140
+ else if (!names.includes(found.name))
141
+ names.push(found.name);
135
142
  }
136
- return { pinned, warnings };
143
+ return { names, warnings };
137
144
  }
138
145
  /** The `effort` declaration of `model`, or null (or when the model cannot be resolved). */
139
146
  async function effortDecl(registry, orgId, model) {
@@ -187,7 +194,8 @@ function orgAgentDefinition(d, a) {
187
194
  // `subagent_started.definition` keeps its shape (spec 2026-11-04 §3.3); its own `subagents`
188
195
  // block stays: it is the roster the child dispatches from (agent map spec §4.1); pending
189
196
  // connectors are authoring data too (ruling P4-6)
190
- const { skills, instructionFiles: _files, pendingConnectors: _pending, ...rest } = own;
197
+ // `skills.writePolicy` never reaches a child: it governs registration on the agent itself
198
+ const { skills: _skills, instructionFiles: _files, pendingConnectors: _pending, ...rest } = own;
191
199
  const { subagentTools: _filter, ...ownRest } = rest;
192
200
  const definition = {
193
201
  ...ownRest,
@@ -196,17 +204,14 @@ function orgAgentDefinition(d, a) {
196
204
  subagentTools: childFilter(atMaxDepth(a), null),
197
205
  // its policies, then the parent's on top, stricter wins (keys outside its tools are inert)
198
206
  toolPolicies: stricterPolicies(own.toolPolicies ?? {}, a.parent.toolPolicies ?? {}),
199
- ...(skills !== undefined && {
200
- skills: {
201
- orgSkills: skills.orgSkills,
202
- ...(skills.pinned !== undefined && { pinned: skills.pinned }),
203
- },
204
- }),
207
+ // its own skills: what it turns off (skills default-on spec §6.1)
208
+ disabledSkills: own.disabledSkills ?? [],
205
209
  };
206
210
  return {
207
211
  definition,
208
212
  template: { source: "agent", id: agentId, version: a.orgAgent.version },
209
213
  maxSteps: d.config.get().runtime.maxSteps,
214
+ preamble: SUBAGENT_PREAMBLE,
210
215
  warnings: [],
211
216
  model: own.model,
212
217
  tierFallback: false,
@@ -215,9 +220,9 @@ function orgAgentDefinition(d, a) {
215
220
  /**
216
221
  * The effective definition of a sub-agent at its first dispatch (spec §5.3–§5.5):
217
222
  * - `general` / `inline` / `plugin`: the parent's definition narrowed by the template (tools by
218
- * resolved key, `disallowedTools`, {@link CHILD_REMOVED_TOOLS}; policies stricter-wins), the
219
- * template's instructions, pinned = the template's skills the parent selects (general pins
220
- * nothing), `maxSteps = min(template ?? runtime.maxSteps, runtime.maxSteps)`, and the model tier
223
+ * resolved key, `disallowedTools`, {@link CHILD_REMOVED_TOOLS}; policies stricter-wins; skills
224
+ * by its `disallowedSkills`), the template's instructions, its `skills` the child has named in
225
+ * the preamble to load first (general gets no line), `maxSteps = min(template ?? runtime.maxSteps, runtime.maxSteps)`, and the model tier
221
226
  * `tier` (the call's) → the template's → `inherit`; an unmapped tier runs on the parent's model
222
227
  * (`tierFallback`); a template `effort` is set when the resolved model declares it;
223
228
  * - `agent`: the org agent's version that passed the gates (`orgAgent`, from {@link checkOrgAgent}),
@@ -253,7 +258,13 @@ export async function effectiveDefinition(d, a) {
253
258
  };
254
259
  }
255
260
  const toolPolicies = stricterPolicies(parent.toolPolicies ?? {}, template?.toolPolicies ?? {});
256
- const { pinned, warnings } = await pinnedFor(d.db, a, template?.skills ?? [], entry.source === "plugin" ? { plugin: entry.plugin } : null, template?.selectedSkills ?? []);
261
+ // skills default-on (spec §6.1): the parent's catalog, narrowed by the template's
262
+ // `disallowedSkills`; the template's `skills` are named in the preamble, never pinned
263
+ const narrowing = await disallowedSkillRefs(d.db, a.orgId, template?.disallowedSkills);
264
+ const disabledSkills = narrowing.length === 0
265
+ ? (parent.disabledSkills ?? [])
266
+ : canonicalDisabledSkills([...(parent.disabledSkills ?? []), ...narrowing]);
267
+ const { names, warnings } = await skillsToLoad(d.db, { orgId: a.orgId, agentId: a.parentAgentId, disabledSkills }, template?.skills ?? [], entry.source === "inline");
257
268
  const tier = a.tier ?? template?.model ?? "inherit";
258
269
  const m = await resolveTier(d, a.orgId, parent, tier);
259
270
  let modelParams = m.modelParams;
@@ -265,7 +276,6 @@ export async function effectiveDefinition(d, a) {
265
276
  modelParams = { ...modelParams, [decl.key]: v };
266
277
  }
267
278
  }
268
- const parentSkills = parent.skills;
269
279
  const definition = {
270
280
  name: childName(parent.name, entry.type),
271
281
  avatarUrl: parent.avatarUrl,
@@ -277,18 +287,16 @@ export async function effectiveDefinition(d, a) {
277
287
  disabledTools: parent.disabledTools ?? [],
278
288
  subagentTools: childFilter(atMaxDepth(a), template, parent.subagentTools),
279
289
  toolPolicies,
280
- ...((parentSkills !== undefined || pinned.length > 0) && {
281
- skills: {
282
- orgSkills: parentSkills?.orgSkills ?? [],
283
- ...(pinned.length > 0 && { pinned }),
284
- },
285
- }),
290
+ disabledSkills,
286
291
  ...(parent.subagents !== undefined && { subagents: parent.subagents }),
287
292
  };
288
293
  return {
289
294
  definition,
290
295
  template: ref,
291
296
  maxSteps: Math.min(template?.maxSteps ?? runtimeMax, runtimeMax),
297
+ preamble: names.length === 0
298
+ ? SUBAGENT_PREAMBLE
299
+ : `${SUBAGENT_PREAMBLE}\n\n${loadSkillsFirstText(names)}`,
292
300
  warnings,
293
301
  model: m.model,
294
302
  tierFallback: m.tierFallback,
@@ -299,41 +307,30 @@ export async function effectiveDefinition(d, a) {
299
307
  * definition) against `current`, the definition a fresh dispatch would read now: the dispatching
300
308
  * parent run's version for `general` / inline / plugin children, the dispatched org agent's
301
309
  * current version for an org agent child (whose tools are its own at dispatch too, §5.5). Its
302
- * `disabledTools` are both lists together; its `orgSkills` keep only those `current` still
303
- * selects; a pinned id that was one of the frozen org skills goes with it (the agent's own skills
304
- * stay).
310
+ * `disabledTools` and `disabledSkills` are both lists together.
305
311
  */
306
312
  export function narrowFollowUp(frozen, current) {
307
- const disabledTools = canonicalDisabledTools([
308
- ...(frozen.disabledTools ?? []),
309
- ...(current.disabledTools ?? []),
310
- ]);
311
- if (frozen.skills === undefined)
312
- return { disabledTools };
313
- const frozenOrg = new Set(frozen.skills.orgSkills);
314
- const now = new Set(current.skills?.orgSkills ?? []);
315
- const orgSkills = frozen.skills.orgSkills.filter((id) => now.has(id));
316
- const pinned = frozen.skills.pinned?.filter((id) => !frozenOrg.has(id) || now.has(id));
317
- return { disabledTools, skills: { orgSkills, ...(pinned !== undefined && { pinned }) } };
313
+ return {
314
+ disabledTools: canonicalDisabledTools([
315
+ ...(frozen.disabledTools ?? []),
316
+ ...(current.disabledTools ?? []),
317
+ ]),
318
+ disabledSkills: canonicalDisabledSkills([
319
+ ...(frozen.disabledSkills ?? []),
320
+ ...(current.disabledSkills ?? []),
321
+ ]),
322
+ };
318
323
  }
319
324
  /**
320
325
  * The definition a child run uses: the frozen one with its trigger's follow-up narrowing. A
321
- * narrowing logged before tools were on by default (no `disabledTools`) narrows only skills.
326
+ * narrowing logged before tools (or skills) were on by default narrows nothing of that kind.
322
327
  */
323
328
  export function childRunDefinition(frozen, narrowed) {
324
329
  if (narrowed === undefined)
325
330
  return frozen;
326
- const { skills, ...rest } = frozen;
327
- const kept = skills === undefined || narrowed.skills === undefined
328
- ? skills
329
- : {
330
- ...skills,
331
- orgSkills: narrowed.skills.orgSkills,
332
- ...(narrowed.skills.pinned !== undefined && { pinned: narrowed.skills.pinned }),
333
- };
334
331
  return {
335
- ...rest,
332
+ ...frozen,
336
333
  ...(Array.isArray(narrowed.disabledTools) && { disabledTools: narrowed.disabledTools }),
337
- ...(kept !== undefined && { skills: kept }),
334
+ ...(Array.isArray(narrowed.disabledSkills) && { disabledSkills: narrowed.disabledSkills }),
338
335
  };
339
336
  }
@@ -9,7 +9,6 @@ import { childResult, finishedEvent } from "./child.js";
9
9
  import { effectiveDefinition, SubagentTypeGoneError, } from "./definition.js";
10
10
  import { subagentLimits } from "./limits.js";
11
11
  import { auditRefusal, checkOrgAgent, currentAgentDefinition } from "./org-agents.js";
12
- import { SUBAGENT_PREAMBLE } from "./preamble.js";
13
12
  import { findType, GENERAL_PURPOSE_DESCRIPTION, resolveRoster, } from "./roster.js";
14
13
  const refused = (content) => ({ kind: "refused", content });
15
14
  /** The `general-purpose` roster entry (a fork invocation always has it). */
@@ -147,7 +146,7 @@ export async function dispatchSubagent(d, a) {
147
146
  },
148
147
  },
149
148
  definition: eff.definition,
150
- preamble: SUBAGENT_PREAMBLE,
149
+ preamble: eff.preamble,
151
150
  maxSteps: eff.maxSteps,
152
151
  ...([...eff.warnings, ...warnings].length > 0 && {
153
152
  warnings: [...eff.warnings, ...warnings],
@@ -266,7 +265,7 @@ export async function commitDispatchIn(d, a, plan, child) {
266
265
  .executeTakeFirst();
267
266
  const parent = await t
268
267
  .selectFrom("runs")
269
- .select(["status", "subagent_tokens_used", "budget_run_id"])
268
+ .select(["status", "subagent_tokens_used", "budget_run_id", "scheduled_task_run_id"])
270
269
  .where("id", "=", ctx.runId)
271
270
  .forUpdate()
272
271
  .executeTakeFirst();
@@ -367,6 +366,8 @@ export async function commitDispatchIn(d, a, plan, child) {
367
366
  trigger_account_id: ctx.accountId,
368
367
  trigger_seq: task.seq,
369
368
  budget_run_id: budgetRunId,
369
+ // an unattended parent's sub-agents are unattended too (scheduled tasks spec §4)
370
+ scheduled_task_run_id: parent.scheduled_task_run_id,
370
371
  })
371
372
  .execute();
372
373
  await t
@@ -2,6 +2,7 @@
2
2
  * The sub-agent preamble (spec §6.3, agent map spec §4.4, model-visible): rendered in a child's
3
3
  * system text after `BEHAVIOR_RULES` and before its instructions. Frozen into each child's
4
4
  * `subagent_started` at dispatch, and request building reads it from there, so changing this text
5
- * never alters an old child's requests.
5
+ * never alters an old child's requests. A template child's preamble ends with a line naming the
6
+ * template's skills to load first (`effectiveDefinition`, skills default-on spec §6.1).
6
7
  */
7
8
  export declare const SUBAGENT_PREAMBLE: string;
@@ -2,7 +2,8 @@
2
2
  * The sub-agent preamble (spec §6.3, agent map spec §4.4, model-visible): rendered in a child's
3
3
  * system text after `BEHAVIOR_RULES` and before its instructions. Frozen into each child's
4
4
  * `subagent_started` at dispatch, and request building reads it from there, so changing this text
5
- * never alters an old child's requests.
5
+ * never alters an old child's requests. A template child's preamble ends with a line naming the
6
+ * template's skills to load first (`effectiveDefinition`, skills default-on spec §6.1).
6
7
  */
7
8
  export const SUBAGENT_PREAMBLE = "You are a sub-agent. Another agent dispatched you with the task in the first user message. " +
8
9
  "Work on it on your own: the user does not watch this conversation and you cannot ask them " +
@@ -21,7 +21,7 @@ import { KernelEvents } from "../infra/events/kernel-events.js";
21
21
  import { LockService } from "../infra/lock/lock.service.js";
22
22
  import { LockedCron } from "../infra/schedule/locked-cron.decorator.js";
23
23
  import { KERNEL_LOGGER } from "../infra/tokens.js";
24
- import { ApprovalsService } from "../tools/approvals.service.js";
24
+ import { ApprovalsService, NETWORK_ASK_CANCELLED_NOTE, } from "../tools/approvals.service.js";
25
25
  import { APPROVAL_CANCELLED_TEXT, INPUT_CANCELLED_TEXT, RUN_STOPPED_TEXT, ToolPipeline, } from "../tools/pipeline.js";
26
26
  import { QuestionsService } from "../tools/questions.service.js";
27
27
  import { RunAbort } from "./abort.js";
@@ -393,12 +393,22 @@ let Waits = class Waits {
393
393
  const steps = new Set();
394
394
  const approvals = await t
395
395
  .selectFrom("approvals")
396
- .select(["id", "call_id", "tool_key"])
396
+ .select(["id", "call_id", "tool_key", "kind", "detail"])
397
397
  .where("run_id", "=", runId)
398
398
  .orderBy("created_at")
399
+ .orderBy("attempt")
399
400
  .execute();
400
401
  for (const a of approvals) {
401
- cancelled.set(a.call_id, { toolKey: a.tool_key, text: APPROVAL_CANCELLED_TEXT });
402
+ // a network ask's command already ran: its kept result, then why access stays blocked
403
+ // (network ask-to-allow spec §6.7)
404
+ const kept = a.kind === "network" ? a.detail?.result : null;
405
+ cancelled.set(a.call_id, kept
406
+ ? {
407
+ toolKey: a.tool_key,
408
+ text: `${kept.content}\n\n${NETWORK_ASK_CANCELLED_NOTE}`,
409
+ isError: kept.isError,
410
+ }
411
+ : { toolKey: a.tool_key, text: APPROVAL_CANCELLED_TEXT });
402
412
  const step = await this.approvalStep(t, conversationId, a.id);
403
413
  if (step !== null)
404
414
  steps.add(step);
@@ -1090,7 +1100,7 @@ let Waits = class Waits {
1090
1100
  callId: b.id,
1091
1101
  toolKey: c?.toolKey ?? b.name ?? "",
1092
1102
  content: c?.text ?? RUN_STOPPED_TEXT,
1093
- isError: true,
1103
+ isError: c?.isError ?? true,
1094
1104
  },
1095
1105
  });
1096
1106
  }