@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
@@ -11,6 +11,7 @@ import { randomUUID } from "node:crypto";
11
11
  import { parseSkillMd, SKILL_ENTRY_FILE } from "@capybara-hq/plugin-sdk";
12
12
  import { Inject, Injectable } from "@nestjs/common";
13
13
  import { sql } from "kysely";
14
+ import { skillDisabled } from "../agents/definition.js";
14
15
  import { offeredNamed } from "../catalog/component-state.js";
15
16
  import { PLATFORM_OWNER } from "../catalog/ownership.js";
16
17
  import { PlatformComponents } from "../catalog/platform-components.js";
@@ -27,12 +28,11 @@ import { TransactionHost } from "../infra/database/transaction-host.js";
27
28
  import { Transactional } from "../infra/database/transactional.decorator.js";
28
29
  import { KERNEL_LOGGER } from "../infra/tokens.js";
29
30
  import { OrgLock } from "../orgs/org-lock.js";
30
- import { textBytesTokens } from "../runtime/context/tokens.js";
31
31
  import { StorageService } from "../storage/storage.service.js";
32
- import { invocationOf, PINNED_SKILLS_LIMITS } from "./catalog.js";
32
+ import { invocationOf } from "./catalog.js";
33
33
  import { cancelRequestIn, } from "./conversation-catalog.js";
34
34
  import { readSkillPackage, skillManifest, } from "./package.js";
35
- import { PLATFORM_SOURCE, platformSkillsOn, platformSource, skillFileStore, skillVersionsById, usableSkills, } from "./usable.js";
35
+ import { agentOwnSkillIds, builtinSkillIds, builtinSkillPlugins, linkedCopyIds, PLATFORM_SOURCE, platformSkillsOn, platformSource, skillFileStore, skillIdsOf, skillVersionsById, usableSkills, } from "./usable.js";
36
36
  /**
37
37
  * The skills named in `skillNames` an org would see twice if catalog item `itemId` brought its
38
38
  * skills (spec §9.2, Decision 8; rule 10 of the plugin scope spec): the org's own usable skills
@@ -130,114 +130,113 @@ const PUT_CONCURRENCY = 4;
130
130
  export const SKILL_BODY_MAX_BYTES = 1024 * 1024;
131
131
  const notFound = () => new ApiError("skill.not_found", "Skill not found");
132
132
  /**
133
- * 在调用方事务里核对 agent 定义引用的组织技能:每个 id 都必须是该组织未删除的 `scope=org` 技能
134
- * (or, phase 2, a platform skill on in the org: skills/usable.ts),
135
- * 否则 `validation_failed`(path `skills.orgSkills.<i>`);不可重复。调用方须已锁组织行(技能删除同样锁组织行,二者串行)。
136
- * `kept`:当前版本里已有的引用(保存时合法),修改时不再核对——技能之后被删也不挡住其他改动(运行时由 T14 忽略已删除的技能)。
133
+ * Checks `disabledSkills` of an agent definition in the caller's transaction (skills default-on
134
+ * spec §4); throws 400 `validation_failed` with one detail per problem at `disabledSkills.<i>`:
135
+ * - a plugin entry must name a plugin with at least one skill usable in the org, and each name must
136
+ * be a skill of it;
137
+ * - a skill entry must name a usable org skill without a plugin;
138
+ * - a builtin plugin, a builtin skill, the agent's own skill or an org skill it shared cannot be
139
+ * turned off.
140
+ * What the current version already turns off (`kept`) is not checked again: a whole entry, or the
141
+ * names a plugin entry kept, so a plugin switched off or uninstalled later never blocks other edits.
137
142
  */
138
- export async function assertOrgSkills(db, orgId, ids, kept = new Set()) {
139
- const details = [];
140
- const seen = new Set();
141
- ids.forEach((id, i) => {
142
- if (seen.has(id))
143
- details.push({ path: `skills.orgSkills.${i}`, message: "Duplicate skill" });
144
- seen.add(id);
143
+ export async function assertDisabledSkills(db, a) {
144
+ const kept = a.kept ?? [];
145
+ const keptPlugin = new Map();
146
+ const keptIds = new Set();
147
+ for (const r of kept) {
148
+ if (r.kind === "skill")
149
+ keptIds.add(r.skillId);
150
+ else
151
+ keptPlugin.set(r.plugin, r.skills === "all" ? "all" : new Set(r.skills));
152
+ }
153
+ const toCheck = [];
154
+ a.disabled.forEach((r, i) => {
155
+ if (r.kind === "skill") {
156
+ if (!keptIds.has(r.skillId))
157
+ toCheck.push({ i, r });
158
+ return;
159
+ }
160
+ const k = keptPlugin.get(r.plugin);
161
+ if (k === "all")
162
+ return;
163
+ if (k === undefined) {
164
+ toCheck.push({ i, r });
165
+ return;
166
+ }
167
+ // the plugin was turned off before: only the names added now are checked
168
+ if (r.skills === "all")
169
+ return;
170
+ const added = r.skills.filter((n) => !k.has(n));
171
+ if (added.length > 0)
172
+ toCheck.push({ i, r, names: added });
145
173
  });
146
- const toCheck = [...seen].filter((id) => !kept.has(id));
147
- if (toCheck.length > 0) {
148
- // The org's skills, its copies linked to a platform skill while that one is on in the org
149
- // (as `assertPinnedSkills` sees them), and platform skills on in the org (phase 2)
150
- const found = [...(await skillVersionsById(db, orgId, toCheck)).values()]
151
- .filter((r) => r.scope === "org")
152
- .map((r) => r.id);
153
- const live = new Set([...kept, ...found]);
154
- ids.forEach((id, i) => {
155
- if (!live.has(id)) {
174
+ if (toCheck.length === 0)
175
+ return;
176
+ const usable = await usableSkills(db, a.orgId);
177
+ const linked = await linkedCopyIds(db, a.orgId, usable.flatMap((u) => (u.origin === "platform" ? [u.id] : [])));
178
+ const builtinPlugins = await builtinSkillPlugins(db);
179
+ const builtinIds = new Set(await builtinSkillIds(db, a.orgId));
180
+ const { own, shared } = a.agentId === null
181
+ ? { own: [], shared: [] }
182
+ : await agentOwnSkillIds(db, { orgId: a.orgId, agentId: a.agentId });
183
+ const fixedIds = new Set([...own, ...shared]);
184
+ const details = [];
185
+ for (const { i, r, names } of toCheck) {
186
+ const path = `disabledSkills.${i}`;
187
+ if (r.kind === "skill") {
188
+ if (fixedIds.has(r.skillId)) {
156
189
  details.push({
157
- path: `skills.orgSkills.${i}`,
158
- message: `Skill ${id} does not exist in this organization or has been deleted`,
190
+ path,
191
+ message: `Skill ${r.skillId} is this agent's own and cannot be turned off`,
192
+ });
193
+ continue;
194
+ }
195
+ const skill = usable.find((u) => skillIdsOf(u, linked).includes(r.skillId));
196
+ if (skill === undefined || skill.plugin !== null) {
197
+ details.push({
198
+ path,
199
+ message: `Skill ${r.skillId} is not a skill of this organization without a plugin`,
159
200
  });
160
201
  }
161
- });
162
- }
163
- if (details.length > 0) {
164
- throw new ApiError("validation_failed", "Invalid skill references", details);
165
- }
166
- }
167
- /**
168
- * Checks `skills.pinned` of an agent definition in the caller's transaction (the org row is locked,
169
- * like {@link assertOrgSkills}); throws 400 `agent.pinned_invalid` with one detail per problem
170
- * (`{ skill, reason, totalBytes? }`):
171
- * - `duplicate`: an id listed twice; `too_many`: every id past {@link PINNED_SKILLS_LIMITS}.count;
172
- * - each newly added id (not in `kept`, the current definition's pinned ids) must be a live org
173
- * skill listed in `skills.orgSkills` (else `not_selected`) or a live skill of this agent
174
- * (`agentId`; null when creating), else `not_found`. Kept ids are not re-checked: a pinned skill
175
- * deleted later does not block other edits (the run ignores it);
176
- * - `manual_only` (phase D): a newly added id whose current version is manual-only
177
- * (`invocation.model === false`); a kept one that became manual-only is dropped at run time;
178
- * - `too_large`: the current SKILL.md sizes of the live pinned skills total more than
179
- * {@link PINNED_SKILLS_LIMITS}.totalBytes (named by the first skill past the limit). Checked only
180
- * when the pinned list changed: a pinned skill's new version never blocks an unrelated edit (the
181
- * run keeps what fits).
182
- */
183
- export async function assertPinnedSkills(db, orgId, agentId, skills, kept = []) {
184
- const pinned = skills?.pinned;
185
- if (pinned === undefined)
186
- return;
187
- const details = [];
188
- const seen = new Set();
189
- const unique = [];
190
- for (const id of pinned) {
191
- if (seen.has(id)) {
192
- details.push({ skill: id, reason: "duplicate" });
193
202
  continue;
194
203
  }
195
- seen.add(id);
196
- if (unique.length >= PINNED_SKILLS_LIMITS.count) {
197
- details.push({ skill: id, reason: "too_many" });
204
+ if (builtinPlugins.has(r.plugin)) {
205
+ details.push({
206
+ path,
207
+ message: `The skills of built-in plugin "${r.plugin}" cannot be turned off`,
208
+ });
198
209
  continue;
199
210
  }
200
- unique.push(id);
201
- }
202
- // org and agent skills, org copies linked to a platform skill (its current version) and platform
203
- // skills on in the org (phase 2)
204
- const byId = new Map([...(await skillVersionsById(db, orgId, unique)).values()].map((r) => [
205
- r.id,
206
- { id: r.id, scope: r.scope, agent_id: r.agentId, manifest: r.manifest },
207
- ]));
208
- const keptSet = new Set(kept);
209
- const selected = new Set(skills?.orgSkills ?? []);
210
- for (const id of unique) {
211
- if (keptSet.has(id))
211
+ const ofPlugin = usable.filter((u) => u.plugin === r.plugin);
212
+ if (ofPlugin.length === 0) {
213
+ details.push({ path, message: `Plugin "${r.plugin}" has no skills in this organization` });
212
214
  continue;
213
- const r = byId.get(id);
214
- const own = r?.scope === "agent" && agentId !== null && r.agent_id === agentId;
215
- if (!r || (r.scope === "agent" && !own))
216
- details.push({ skill: id, reason: "not_found" });
217
- else if (r.scope === "org" && !selected.has(id))
218
- details.push({ skill: id, reason: "not_selected" });
219
- else if (!invocationOf(r.manifest).model)
220
- details.push({ skill: id, reason: "manual_only" });
221
- }
222
- const changed = pinned.length !== kept.length || pinned.some((id, i) => kept[i] !== id);
223
- if (details.length === 0 && changed) {
224
- let total = 0;
225
- let over;
226
- for (const id of unique) {
227
- const size = byId.get(id)?.manifest.files.find((f) => f.path === SKILL_ENTRY_FILE)?.size ?? 0;
228
- total += size;
229
- if (over === undefined && total > PINNED_SKILLS_LIMITS.totalBytes)
230
- over = id;
231
215
  }
232
- if (over !== undefined)
233
- details.push({ skill: over, reason: "too_large", totalBytes: total });
216
+ if (r.skills === "all")
217
+ continue;
218
+ for (const name of names ?? r.skills) {
219
+ const skill = ofPlugin.find((u) => u.name === name);
220
+ if (skill === undefined) {
221
+ details.push({ path, message: `Plugin "${r.plugin}" has no skill "${name}"` });
222
+ }
223
+ else if (builtinIds.has(skill.id) ||
224
+ (skill.platformSkillId !== undefined && builtinIds.has(skill.platformSkillId))) {
225
+ details.push({ path, message: `Built-in skill "${name}" cannot be turned off` });
226
+ }
227
+ else if (fixedIds.has(skill.id)) {
228
+ details.push({
229
+ path,
230
+ message: `Skill "${name}" was shared by this agent and cannot be turned off`,
231
+ });
232
+ }
233
+ }
234
234
  }
235
235
  if (details.length > 0) {
236
- throw new ApiError("agent.pinned_invalid", `Invalid pinned skills: ${details.map((d) => `${d.skill} (${d.reason})`).join(", ")}`, details);
236
+ throw new ApiError("validation_failed", "Invalid skill references", details);
237
237
  }
238
238
  }
239
239
  const summary = (r) => {
240
- const entryBytes = r.manifest?.files.find((f) => f.path === SKILL_ENTRY_FILE)?.size ?? 0;
241
240
  const inv = r.manifest ? invocationOf(r.manifest) : { model: true, user: true };
242
241
  return {
243
242
  id: r.id,
@@ -251,9 +250,6 @@ const summary = (r) => {
251
250
  updatedAt: r.updated_at,
252
251
  plugin: r.item_name,
253
252
  sourceFormat: r.source_format ?? "capybara",
254
- suggestPinned: r.suggest_pinned ?? false,
255
- entryBytes,
256
- tokenEstimate: textBytesTokens(entryBytes),
257
253
  manual: inv.model === false,
258
254
  fork: inv.fork !== undefined,
259
255
  origin: "org",
@@ -276,7 +272,6 @@ const platformSummaryQuery = (db) => db
276
272
  "p.owner_org_id",
277
273
  "owner.name as owner_name",
278
274
  "v.source_format",
279
- "v.suggest_pinned",
280
275
  "v.manifest",
281
276
  ])
282
277
  .where("p.deleted_at", "is", null);
@@ -293,7 +288,6 @@ const platformSummary = (r) => ({
293
288
  updated_at: r.updated_at,
294
289
  item_name: r.plugin_name,
295
290
  source_format: r.source_format,
296
- suggest_pinned: r.suggest_pinned,
297
291
  manifest: r.manifest,
298
292
  shareable: false,
299
293
  }),
@@ -304,7 +298,7 @@ const platformSummary = (r) => ({
304
298
  });
305
299
  /**
306
300
  * Skills with their summary columns: the catalog item name (provenance) and the current version's
307
- * source format, pinned suggestion and manifest.
301
+ * source format and manifest.
308
302
  */
309
303
  const summaryQuery = (db) => db
310
304
  .selectFrom("skills as s")
@@ -322,7 +316,6 @@ const summaryQuery = (db) => db
322
316
  "s.updated_at",
323
317
  "i.name as item_name",
324
318
  "v.source_format",
325
- "v.suggest_pinned",
326
319
  "v.manifest",
327
320
  "s.shareable",
328
321
  ]);
@@ -629,7 +622,6 @@ let SkillsService = class SkillsService {
629
622
  created_by: actorAccountId,
630
623
  ...provenance,
631
624
  source_format: opts.catalog?.format ?? "capybara",
632
- suggest_pinned: opts.catalog?.suggestPinned ?? false,
633
625
  })
634
626
  .execute();
635
627
  await audit(this.db.db, {
@@ -728,7 +720,9 @@ let SkillsService = class SkillsService {
728
720
  /**
729
721
  * The org skill library, sorted by name: the org's live `scope=org` skills except copies linked
730
722
  * to a platform skill without a pin, and the platform skills on in the org (phase 2,
731
- * `usableSkills`; `origin` tells them apart), each with the ids of those copies (`linkedIds`).
723
+ * `usableSkills`; `origin` tells them apart), each with the ids of those copies (`linkedIds`);
724
+ * every item carries `builtin`: true for a platform skill of a builtin plugin or the org's pinned
725
+ * copy of one (every agent has it, none can turn it off).
732
726
  */
733
727
  async list(orgId) {
734
728
  const usable = await usableSkills(this.db.db, orgId);
@@ -740,11 +734,14 @@ let SkillsService = class SkillsService {
740
734
  u.source.startsWith(PLATFORM_SOURCE)
741
735
  ? [[u.id, u.platformSkillId]]
742
736
  : []));
737
+ // builtin plugins' skills (and the org's pinned copies of them): every agent has them
738
+ const builtin = new Set(await builtinSkillIds(this.db.db, orgId));
743
739
  const own = orgIds.length === 0
744
740
  ? []
745
- : await Promise.all((await summaryQuery(this.db.db).where("s.id", "in", orgIds).orderBy("s.name").execute()).map((r) => {
741
+ : await Promise.all((await summaryQuery(this.db.db).where("s.id", "in", orgIds).orderBy("s.name").execute()).map(async (r) => {
746
742
  const to = promotedTo.get(r.id);
747
- return to === undefined ? summary(r) : this.promotedSummary(r.id, to);
743
+ const s = to === undefined ? summary(r) : await this.promotedSummary(r.id, to);
744
+ return { ...s, builtin: builtin.has(r.id) };
748
745
  }));
749
746
  if (platformIds.length === 0)
750
747
  return own;
@@ -763,7 +760,11 @@ let SkillsService = class SkillsService {
763
760
  const k = l.platform_skill_id;
764
761
  linked.set(k, [...(linked.get(k) ?? []), l.id]);
765
762
  }
766
- const platform = (await platformSummaryQuery(this.db.db).where("p.id", "in", platformIds).execute()).map((r) => ({ ...platformSummary(r), linkedIds: linked.get(r.id) ?? [] }));
763
+ const platform = (await platformSummaryQuery(this.db.db).where("p.id", "in", platformIds).execute()).map((r) => ({
764
+ ...platformSummary(r),
765
+ linkedIds: linked.get(r.id) ?? [],
766
+ builtin: builtin.has(r.id),
767
+ }));
767
768
  return [...own, ...platform].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : a.id < b.id ? -1 : 1);
768
769
  }
769
770
  /**
@@ -816,6 +817,66 @@ let SkillsService = class SkillsService {
816
817
  * 404 while that skill is off in the org); a pinned copy keeps its own (Task 10).
817
818
  */
818
819
  async get(orgId, skillId) {
820
+ const detail = await this.detail(orgId, skillId);
821
+ return { ...detail, agentsOff: await this.agentsOff(orgId, detail) };
822
+ }
823
+ /**
824
+ * How many of the org's live agents turn the skill off in their current version (skills
825
+ * default-on spec §10: 「N 个智能体关闭了它」): matched by the rule of `agentSkills` against the
826
+ * skill as the org's usable set holds it. A builtin skill, one not usable in the org and an org
827
+ * skill for the agent that shared it count 0.
828
+ */
829
+ async agentsOff(orgId, skill) {
830
+ const db = this.db.db;
831
+ const usable = await usableSkills(db, orgId);
832
+ const linked = await linkedCopyIds(db, orgId, usable.flatMap((u) => (u.origin === "platform" ? [u.id] : [])));
833
+ const u = usable.find((x) => skillIdsOf(x, linked).includes(skill.id));
834
+ if (u === undefined)
835
+ return 0;
836
+ const ids = skillIdsOf(u, linked);
837
+ if (u.plugin !== null &&
838
+ u.origin === "platform" &&
839
+ (await builtinSkillPlugins(db)).has(u.plugin))
840
+ return 0;
841
+ const builtinIds = new Set(await builtinSkillIds(db, orgId));
842
+ if (ids.some((id) => builtinIds.has(id)))
843
+ return 0;
844
+ const rows = await db
845
+ .selectFrom("agents")
846
+ .innerJoin("agent_versions", (j) => j
847
+ .onRef("agent_versions.agent_id", "=", "agents.id")
848
+ .onRef("agent_versions.version", "=", "agents.current_version"))
849
+ .select([
850
+ "agents.id",
851
+ sql `agent_versions.definition->'disabledSkills'`.as("disabled_skills"),
852
+ ])
853
+ .where("agents.org_id", "=", orgId)
854
+ .where("agents.deleted_at", "is", null)
855
+ .where(sql `jsonb_array_length(coalesce(agent_versions.definition->'disabledSkills', '[]'::jsonb)) > 0`)
856
+ .execute();
857
+ if (rows.length === 0)
858
+ return 0;
859
+ // the agent that shared an org skill always has it
860
+ const sharedBy = await db
861
+ .selectFrom("skills")
862
+ .select("origin_agent_id")
863
+ .where("org_id", "=", orgId)
864
+ .where("scope", "=", "org")
865
+ .where("deleted_at", "is", null)
866
+ .where("id", "in", ids)
867
+ .where("origin_agent_id", "is not", null)
868
+ .execute();
869
+ const sharers = new Set(sharedBy.map((r) => r.origin_agent_id));
870
+ return rows.filter((r) => !sharers.has(r.id) &&
871
+ Array.isArray(r.disabled_skills) &&
872
+ skillDisabled(r.disabled_skills, {
873
+ plugin: u.plugin,
874
+ name: u.name,
875
+ ids,
876
+ })).length;
877
+ }
878
+ /** The skill's detail without `agentsOff` (no agents scan; for names and checks). */
879
+ async detail(orgId, skillId) {
819
880
  const link = await this.db
820
881
  .selectFrom("skills")
821
882
  .select("platform_skill_id")
@@ -1,4 +1,5 @@
1
1
  import type { Logger, ObjectStore } from "@capybara-hq/plugin-sdk";
2
+ import { type DisabledSkillRef } from "../agents/definition.js";
2
3
  import type { KernelSchemaDb, SkillManifest, SourceFormat } from "../db/kernel-schema.js";
3
4
  /** The `source` prefix of a platform skill version in a snapshot or an invocation record. */
4
5
  export declare const PLATFORM_SOURCE = "platform:";
@@ -30,6 +31,13 @@ export interface UsableSkill {
30
31
  /** The platform skill whose content this is (a platform skill, or a linked org copy). */
31
32
  platformSkillId?: string;
32
33
  }
34
+ /**
35
+ * A resolver's logger: name clashes are warnings; `debug` (the kernel logger has it) takes the ones
36
+ * nobody chose (a builtin skill no agent selected, shadowed for every resolution).
37
+ */
38
+ type ResolveLog = Pick<Logger, "warn"> & {
39
+ debug?: (msg: string, fields?: Record<string, unknown>) => void;
40
+ };
33
41
  /** A usable or selected skill with what the resolvers need beyond {@link UsableSkill}. */
34
42
  export interface SkillVersionRow extends UsableSkill {
35
43
  /** `agent`: an agent's own skill (never in the org library). Platform skills are `org`. */
@@ -57,18 +65,58 @@ export declare function pinnedSkillLinksServed(db: KernelSchemaDb, orgId: string
57
65
  * while the platform skill is on in the org; a pinned copy as its own version, while its platform
58
66
  * skill is on in the org (ruling P2-18); a platform skill id while it is on in the org.
59
67
  */
60
- export declare function skillVersionsById(db: KernelSchemaDb, orgId: string, ids: readonly string[], log?: Pick<Logger, "warn">): Promise<Map<string, SkillVersionRow>>;
68
+ export declare function skillVersionsById(db: KernelSchemaDb, orgId: string, ids: readonly string[], log?: ResolveLog,
69
+ /** Ids nobody selected (builtin skills): a name clash of theirs is logged at `debug`. */
70
+ quiet?: ReadonlySet<string>): Promise<Map<string, SkillVersionRow>>;
71
+ /**
72
+ * The skill ids no agent can turn off (skill authoring spec §5.7, skills default-on spec §3): the
73
+ * live platform skills of the platform's builtin plugins (`catalog_items.builtin`, platform-owned),
74
+ * plus the org's pinned copies of them (a pinned copy shadows its platform skill by name, ruling
75
+ * P2-18). Whether each is on in the org (a component switch, the deployment's disable) is left to
76
+ * the resolvers.
77
+ */
78
+ export declare function builtinSkillIds(db: KernelSchemaDb, orgId: string): Promise<string[]>;
79
+ /**
80
+ * The names of the platform's builtin plugins (`catalog_items.builtin`, platform-owned, live): their
81
+ * skills are always on, and an agent cannot turn them off (skills default-on spec §3).
82
+ */
83
+ export declare function builtinSkillPlugins(db: KernelSchemaDb): Promise<Set<string>>;
84
+ /**
85
+ * The ids of the skills an agent always has, whatever its `disabledSkills` say: its own skills
86
+ * (`scope = 'agent'`) and the org skills it shared (`origin_agent_id`: the agent keeps a shared
87
+ * skill without a definition entry).
88
+ */
89
+ export declare function agentOwnSkillIds(db: KernelSchemaDb, a: {
90
+ orgId: string;
91
+ agentId: string;
92
+ }): Promise<{
93
+ own: string[];
94
+ shared: string[];
95
+ }>;
96
+ /**
97
+ * The org's copies linked to the platform skills `platformIds` without a pin (ruling B2), by
98
+ * platform skill id (the first by id when there are several): such a copy keeps its own id in an
99
+ * agent's catalog, as when it was selected, so the snapshot does not change when a copy gets
100
+ * linked.
101
+ */
102
+ export declare function linkedCopyIds(db: KernelSchemaDb, orgId: string, platformIds: readonly string[]): Promise<Map<string, string>>;
103
+ /**
104
+ * The ids a disabled skill entry may name for `r`: its own, the platform skill it serves and the
105
+ * org's linked copy listed under it (`linked`, from {@link linkedCopyIds}).
106
+ */
107
+ export declare function skillIdsOf(r: UsableSkill, linked: ReadonlyMap<string, string>): string[];
61
108
  /**
62
- * The skills an agent selects, sorted by id: its own skills (`scope = 'agent'`), the org skills
63
- * it shared (`origin_agent_id`: the agent keeps a shared skill without a definition change) and
64
- * the ids of `orgSkills` that resolve ({@link skillVersionsById}: org skills, linked copies,
65
- * platform skills on in the org). Not deduplicated by name.
109
+ * The skills an agent has (skills default-on spec §3), sorted by id: its own skills, the org
110
+ * skills it shared, and every skill on in the org ({@link usableSkillVersions}) minus what
111
+ * `disabledSkills` turns off. A plugin entry matches a skill's `plugin` and name, a skill entry its
112
+ * id (or the platform skill a copy serves). The skills of builtin plugins, the agent's own and its
113
+ * shared ones are never turned off. Not deduplicated by name (`resolveSkills` ranks).
66
114
  */
67
- export declare function selectedSkills(db: KernelSchemaDb, a: {
115
+ export declare function agentSkills(db: KernelSchemaDb, a: {
68
116
  orgId: string;
69
117
  agentId: string;
70
- orgSkills: readonly string[];
71
- }, log?: Pick<Logger, "warn">): Promise<SkillVersionRow[]>;
118
+ disabledSkills: readonly DisabledSkillRef[];
119
+ }, log?: ResolveLog): Promise<SkillVersionRow[]>;
72
120
  /**
73
121
  * The org's usable skills, sorted by name: its own live org skills (`scope = 'org'`, unlinked, or
74
122
  * pinned while their platform skill is on in the org, ruling P2-18) and the platform skills on in
@@ -80,3 +128,4 @@ export declare function selectedSkills(db: KernelSchemaDb, a: {
80
128
  export declare function usableSkills(db: KernelSchemaDb, orgId: string, log?: Pick<Logger, "warn">): Promise<UsableSkill[]>;
81
129
  /** {@link usableSkills} with each skill's manifest and format. */
82
130
  export declare function usableSkillVersions(db: KernelSchemaDb, orgId: string, log?: Pick<Logger, "warn">): Promise<SkillVersionRow[]>;
131
+ export {};