@capybara-hq/kernel 0.1.0-rc.20 → 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 (247) hide show
  1. package/bootstrap.json +10 -1
  2. package/dist/agents/admin-agents.d.ts +16 -3
  3. package/dist/agents/admin-agents.js +65 -7
  4. package/dist/agents/agents.schemas.d.ts +24 -6
  5. package/dist/agents/agents.service.d.ts +4 -3
  6. package/dist/agents/agents.service.js +39 -26
  7. package/dist/agents/definition.d.ts +44 -6
  8. package/dist/agents/definition.js +86 -18
  9. package/dist/agents/from-template.d.ts +6 -3
  10. package/dist/agents/from-template.js +57 -44
  11. package/dist/agents/org-templates.js +97 -41
  12. package/dist/agents/templates.d.ts +6 -0
  13. package/dist/agents/templates.js +15 -1
  14. package/dist/catalog/admin-catalog.controller.d.ts +2 -4
  15. package/dist/catalog/admin-catalog.controller.js +2 -6
  16. package/dist/catalog/catalog.module.js +3 -0
  17. package/dist/catalog/claude/report.d.ts +9 -2
  18. package/dist/catalog/claude/report.js +1 -0
  19. package/dist/catalog/claude/translate.js +1 -1
  20. package/dist/catalog/component-promotion.js +1 -2
  21. package/dist/catalog/component-state.d.ts +13 -1
  22. package/dist/catalog/component-state.js +14 -5
  23. package/dist/catalog/marketplaces.service.d.ts +1 -1
  24. package/dist/catalog/marketplaces.service.js +2 -1
  25. package/dist/catalog/org-catalog.controller.d.ts +13 -3
  26. package/dist/catalog/org-catalog.controller.js +26 -4
  27. package/dist/catalog/org-catalog.schemas.d.ts +13 -0
  28. package/dist/catalog/org-catalog.schemas.js +34 -0
  29. package/dist/catalog/org-plugin-uploads.controller.js +0 -1
  30. package/dist/catalog/org-plugin-uploads.d.ts +0 -1
  31. package/dist/catalog/org-plugin-uploads.js +0 -3
  32. package/dist/catalog/org-plugin-uploads.schemas.d.ts +0 -1
  33. package/dist/catalog/org-plugin-uploads.schemas.js +0 -2
  34. package/dist/catalog/platform-components.d.ts +0 -1
  35. package/dist/catalog/platform-components.js +3 -8
  36. package/dist/catalog/plugin-import.d.ts +0 -8
  37. package/dist/catalog/plugin-import.js +4 -35
  38. package/dist/catalog/plugin-install.d.ts +2 -2
  39. package/dist/catalog/plugin-install.js +2 -2
  40. package/dist/catalog/plugin-package.d.ts +7 -0
  41. package/dist/catalog/plugin-package.js +27 -1
  42. package/dist/catalog/plugin-upgrade.d.ts +5 -6
  43. package/dist/catalog/plugin-upgrade.js +5 -23
  44. package/dist/catalog/requests.service.d.ts +66 -10
  45. package/dist/catalog/requests.service.js +196 -15
  46. package/dist/channels/actions.d.ts +2 -0
  47. package/dist/channels/actions.js +19 -4
  48. package/dist/channels/cards.d.ts +16 -2
  49. package/dist/channels/cards.js +40 -7
  50. package/dist/channels/channels.module.js +3 -0
  51. package/dist/channels/outbound.d.ts +22 -1
  52. package/dist/channels/outbound.js +116 -7
  53. package/dist/channels/phrases.d.ts +25 -0
  54. package/dist/channels/phrases.js +19 -0
  55. package/dist/channels/threads.d.ts +12 -0
  56. package/dist/channels/threads.js +34 -0
  57. package/dist/config/schema.d.ts +23 -1
  58. package/dist/config/schema.js +105 -5
  59. package/dist/conversations/conversations.service.d.ts +42 -9
  60. package/dist/conversations/conversations.service.js +57 -25
  61. package/dist/conversations/events.d.ts +106 -11
  62. package/dist/conversations/events.js +121 -18
  63. package/dist/conversations/message-context.d.ts +6 -3
  64. package/dist/conversations/message-context.js +14 -10
  65. package/dist/conversations/queue.d.ts +15 -2
  66. package/dist/conversations/queue.js +22 -3
  67. package/dist/conversations/queue.service.d.ts +12 -6
  68. package/dist/conversations/queue.service.js +36 -13
  69. package/dist/db/kernel-schema.d.ts +105 -3
  70. package/dist/devices/conversation-devices.d.ts +8 -1
  71. package/dist/devices/conversation-devices.js +8 -0
  72. package/dist/devices/devices.controller.d.ts +21 -4
  73. package/dist/devices/devices.controller.js +46 -8
  74. package/dist/devices/devices.schemas.d.ts +9 -1
  75. package/dist/devices/devices.schemas.js +11 -3
  76. package/dist/devices/devices.service.d.ts +176 -4
  77. package/dist/devices/devices.service.js +341 -6
  78. package/dist/devices/dto.d.ts +56 -3
  79. package/dist/devices/dto.js +51 -1
  80. package/dist/devices/public-suffix.d.ts +6 -0
  81. package/dist/devices/public-suffix.js +79 -0
  82. package/dist/errors.d.ts +46 -5
  83. package/dist/errors.js +46 -5
  84. package/dist/evals/reconstruct.d.ts +18 -13
  85. package/dist/evals/reconstruct.js +50 -36
  86. package/dist/evals/recorded-tools.d.ts +7 -7
  87. package/dist/evals/recorded-tools.js +4 -3
  88. package/dist/evals/trajectory.d.ts +6 -1
  89. package/dist/evals/trajectory.js +7 -0
  90. package/dist/extensions/bootstrap.d.ts +49 -10
  91. package/dist/extensions/bootstrap.js +104 -27
  92. package/dist/extensions/package.js +2 -2
  93. package/dist/http/api.module.js +5 -0
  94. package/dist/inbox/inbox.module.js +2 -1
  95. package/dist/inbox/inbox.service.d.ts +19 -4
  96. package/dist/inbox/inbox.service.js +14 -3
  97. package/dist/infra/config/kernel-config.service.js +11 -0
  98. package/dist/infra/events/kernel-events.d.ts +2 -1
  99. package/dist/lifecycle/kernel-lifecycle.d.ts +5 -1
  100. package/dist/lifecycle/kernel-lifecycle.js +16 -4
  101. package/dist/local-devices/device-policy.service.d.ts +65 -0
  102. package/dist/local-devices/device-policy.service.js +217 -0
  103. package/dist/local-devices/local-device-gateway.js +4 -1
  104. package/dist/local-devices/local-device-provider.d.ts +40 -3
  105. package/dist/local-devices/local-device-provider.js +109 -7
  106. package/dist/local-devices/local-devices.module.d.ts +2 -1
  107. package/dist/local-devices/local-devices.module.js +19 -3
  108. package/dist/local-devices/machines.d.ts +14 -3
  109. package/dist/local-devices/machines.js +41 -3
  110. package/dist/local-devices/network-grants.d.ts +104 -0
  111. package/dist/local-devices/network-grants.js +288 -0
  112. package/dist/local-devices/policy-summary.d.ts +20 -0
  113. package/dist/local-devices/policy-summary.js +63 -0
  114. package/dist/orgs/orgs.module.js +4 -10
  115. package/dist/orgs/roles.d.ts +1 -1
  116. package/dist/orgs/roles.js +4 -0
  117. package/dist/orgs/settings.controller.js +2 -1
  118. package/dist/orgs/settings.service.d.ts +164 -12
  119. package/dist/orgs/settings.service.js +212 -24
  120. package/dist/platform/exclusions.js +11 -1
  121. package/dist/platform/operation.js +4 -0
  122. package/dist/platform/ops/admin-items.ops.js +1 -1
  123. package/dist/platform/ops/agent-skills.ops.js +2 -2
  124. package/dist/platform/ops/agent-templates.ops.js +2 -2
  125. package/dist/platform/ops/agents.ops.js +11 -15
  126. package/dist/platform/ops/devices.ops.js +3 -1
  127. package/dist/platform/ops/inbox.ops.js +19 -0
  128. package/dist/platform/ops/org-settings.ops.js +14 -5
  129. package/dist/platform/ops/platform.ops.d.ts +9 -1
  130. package/dist/platform/ops/platform.ops.js +34 -12
  131. package/dist/platform/ops/requests.ops.js +3 -2
  132. package/dist/platform/ops/schedules.ops.d.ts +21 -0
  133. package/dist/platform/ops/schedules.ops.js +470 -0
  134. package/dist/platform/ops/skills.ops.js +3 -3
  135. package/dist/platform/platform-ops.module.d.ts +2 -1
  136. package/dist/platform/platform-ops.module.js +5 -0
  137. package/dist/platform/route-schemas.js +3 -0
  138. package/dist/roles/worker.module.js +3 -0
  139. package/dist/runtime/context/build.js +13 -4
  140. package/dist/runtime/context/compaction.js +6 -3
  141. package/dist/runtime/context/device-paths.d.ts +43 -21
  142. package/dist/runtime/context/device-paths.js +104 -21
  143. package/dist/runtime/context/run-context.d.ts +9 -0
  144. package/dist/runtime/context/run-context.js +8 -0
  145. package/dist/runtime/context/skills.d.ts +14 -1
  146. package/dist/runtime/context/skills.js +36 -5
  147. package/dist/runtime/maintenance.d.ts +4 -2
  148. package/dist/runtime/maintenance.js +16 -5
  149. package/dist/runtime/run-finish.d.ts +6 -1
  150. package/dist/runtime/run-finish.js +16 -2
  151. package/dist/runtime/run-queue.js +21 -2
  152. package/dist/runtime/run-worker.js +14 -33
  153. package/dist/runtime/runtime.module.js +3 -0
  154. package/dist/runtime/subagents/definition.d.ts +32 -14
  155. package/dist/runtime/subagents/definition.js +106 -109
  156. package/dist/runtime/subagents/dispatch.js +4 -3
  157. package/dist/runtime/subagents/preamble.d.ts +2 -1
  158. package/dist/runtime/subagents/preamble.js +2 -1
  159. package/dist/runtime/waits.js +14 -4
  160. package/dist/sandbox/sandbox.service.d.ts +120 -10
  161. package/dist/sandbox/sandbox.service.js +335 -28
  162. package/dist/sandbox/tiers.d.ts +86 -0
  163. package/dist/sandbox/tiers.js +96 -0
  164. package/dist/schedules/effective-settings.d.ts +16 -0
  165. package/dist/schedules/effective-settings.js +17 -0
  166. package/dist/schedules/errors.d.ts +8 -0
  167. package/dist/schedules/errors.js +8 -0
  168. package/dist/schedules/fire.d.ts +118 -0
  169. package/dist/schedules/fire.js +625 -0
  170. package/dist/schedules/grant-rules.d.ts +94 -0
  171. package/dist/schedules/grant-rules.js +126 -0
  172. package/dist/schedules/job-ids.d.ts +32 -0
  173. package/dist/schedules/job-ids.js +27 -0
  174. package/dist/schedules/pause.d.ts +9 -0
  175. package/dist/schedules/pause.js +33 -0
  176. package/dist/schedules/run-tracker.d.ts +81 -0
  177. package/dist/schedules/run-tracker.js +333 -0
  178. package/dist/schedules/scan.job.d.ts +64 -0
  179. package/dist/schedules/scan.job.js +303 -0
  180. package/dist/schedules/schedule-math.d.ts +31 -0
  181. package/dist/schedules/schedule-math.js +223 -0
  182. package/dist/schedules/scheduled-tasks.service.d.ts +351 -0
  183. package/dist/schedules/scheduled-tasks.service.js +1193 -0
  184. package/dist/schedules/schedules.controller.d.ts +68 -0
  185. package/dist/schedules/schedules.controller.js +242 -0
  186. package/dist/schedules/schedules.module.d.ts +16 -0
  187. package/dist/schedules/schedules.module.js +65 -0
  188. package/dist/schedules/schedules.schemas.d.ts +316 -0
  189. package/dist/schedules/schedules.schemas.js +186 -0
  190. package/dist/schedules/store.d.ts +81 -0
  191. package/dist/schedules/store.js +390 -0
  192. package/dist/schedules/store.module.d.ts +6 -0
  193. package/dist/schedules/store.module.js +21 -0
  194. package/dist/schedules/types.d.ts +108 -0
  195. package/dist/schedules/types.js +1 -0
  196. package/dist/schedules/unattended.d.ts +117 -0
  197. package/dist/schedules/unattended.js +228 -0
  198. package/dist/setup/oauth-token-probe.js +8 -4
  199. package/dist/skills/agent-skills.service.d.ts +4 -8
  200. package/dist/skills/agent-skills.service.js +18 -53
  201. package/dist/skills/catalog.d.ts +65 -62
  202. package/dist/skills/catalog.js +109 -206
  203. package/dist/skills/conversation-catalog.d.ts +3 -3
  204. package/dist/skills/conversation-catalog.js +5 -12
  205. package/dist/skills/invoke.d.ts +2 -2
  206. package/dist/skills/skills.controller.d.ts +3 -1
  207. package/dist/skills/skills.service.d.ts +38 -37
  208. package/dist/skills/skills.service.js +168 -107
  209. package/dist/skills/usable.d.ts +57 -8
  210. package/dist/skills/usable.js +172 -38
  211. package/dist/tools/approvals.controller.d.ts +4 -2
  212. package/dist/tools/approvals.controller.js +17 -2
  213. package/dist/tools/approvals.schemas.d.ts +1 -0
  214. package/dist/tools/approvals.schemas.js +3 -1
  215. package/dist/tools/approvals.service.d.ts +182 -7
  216. package/dist/tools/approvals.service.js +597 -13
  217. package/dist/tools/builtin-names.d.ts +25 -4
  218. package/dist/tools/builtin-names.js +45 -4
  219. package/dist/tools/builtins/builtin-tools.d.ts +8 -0
  220. package/dist/tools/builtins/builtin-tools.js +23 -2
  221. package/dist/tools/builtins/sandbox/bash.js +16 -7
  222. package/dist/tools/builtins/sandbox/common.d.ts +1 -1
  223. package/dist/tools/builtins/sandbox/common.js +33 -10
  224. package/dist/tools/builtins/sandbox/edit.js +7 -3
  225. package/dist/tools/builtins/sandbox/file-state.d.ts +31 -1
  226. package/dist/tools/builtins/sandbox/file-state.js +33 -3
  227. package/dist/tools/builtins/sandbox/write.js +8 -4
  228. package/dist/tools/builtins/schedules.d.ts +107 -0
  229. package/dist/tools/builtins/schedules.js +789 -0
  230. package/dist/tools/elicitation.d.ts +2 -0
  231. package/dist/tools/elicitation.js +1 -1
  232. package/dist/tools/fixed-ask.d.ts +7 -0
  233. package/dist/tools/fixed-ask.js +9 -0
  234. package/dist/tools/network-asks.d.ts +109 -0
  235. package/dist/tools/network-asks.js +221 -0
  236. package/dist/tools/pipeline.d.ts +53 -6
  237. package/dist/tools/pipeline.js +202 -13
  238. package/dist/tools/policy.d.ts +21 -8
  239. package/dist/tools/policy.js +63 -9
  240. package/dist/tools/registry.d.ts +10 -1
  241. package/dist/tools/tools.module.js +12 -0
  242. package/package.json +2 -2
  243. package/src/migrations/0113_scheduled_tasks.sql +108 -0
  244. package/src/migrations/0114_network_asks.sql +23 -0
  245. package/src/migrations/0115_network_requests.sql +28 -0
  246. package/src/migrations/0116_skills_default_on.sql +37 -0
  247. package/src/migrations/0117_sandbox_tiers.sql +11 -0
package/bootstrap.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "schemaVersion": 1,
4
4
  "marketplace": {
5
5
  "url": "https://github.com/capybara-hq/plugins.git",
6
- "commit": "14c73d5c51415223326d89414d62b7278ad60745"
6
+ "commit": "050de1403662d2ba04cb96839b742aaa0166c00e"
7
7
  },
8
8
  "plugins": [
9
9
  {
@@ -101,6 +101,15 @@
101
101
  "version": "0.1.0-rc.6",
102
102
  "integrity": "sha512-AOKLpoaBfOQUWnP9nszg9DQWR+6z5gl+ZHoTlHysA9LAeC2h/zipjGE9hY69HF9rueSHzM2kGESJLvXIuQODAA==",
103
103
  "required": false
104
+ },
105
+ {
106
+ "name": "skills-core",
107
+ "source": "npm",
108
+ "npm": "@capybara-hq/plugin-skills-core",
109
+ "version": "0.1.0-rc.0",
110
+ "integrity": "sha512-U3R+B3QcklCQyye22bQU1aJq05oLW4Fr3hfmLHuPFOq5jNt30mDc0zNPSDLr6MFDdUI/OJkkX7wvkyKa+zRPAQ==",
111
+ "required": false,
112
+ "builtin": true
104
113
  }
105
114
  ]
106
115
  }
@@ -1,6 +1,6 @@
1
1
  import { KernelDb } from "../infra/database/kernel-db.js";
2
2
  import { AgentLookup, type AgentVisibility } from "./agent-lookup.js";
3
- import type { AgentDefinition } from "./definition.js";
3
+ import { type AgentDefinition } from "./definition.js";
4
4
  import type { AgentAvatar } from "./profile.js";
5
5
  /** One row of the super admin's cross-org agent list (admin agents spec §3.2). */
6
6
  export interface AdminAgentRow {
@@ -18,6 +18,11 @@ export interface AdminAgentRow {
18
18
  templateId: string;
19
19
  name: string | null;
20
20
  } | null;
21
+ /**
22
+ * How many of the skills on in the org it turns off (skills default-on spec §11): a builtin
23
+ * plugin's skill and an org skill it shared never count, as it always has them.
24
+ */
25
+ skillsOff: number;
21
26
  updatedAt: Date;
22
27
  }
23
28
  /**
@@ -38,8 +43,9 @@ export interface AdminAgentDetail extends AdminAgentRow {
38
43
  versions: number;
39
44
  createdAt: Date;
40
45
  /**
41
- * The skills it uses by name: the selected org skills that resolve in the org (a deleted one is
42
- * left out) and its own skills (`scope: "agent"`). Never a skill body.
46
+ * The skills it has now by name (skills default-on spec §3): every skill on in the org that its
47
+ * `disabledSkills` does not turn off, the org skills it shared and its own skills
48
+ * (`scope: "agent"`). Never a skill body.
43
49
  */
44
50
  skills: {
45
51
  id: string;
@@ -82,6 +88,13 @@ export declare class AdminAgents {
82
88
  }>;
83
89
  /** One live agent of a live org; otherwise `agent.not_found`. */
84
90
  get(agentId: string): Promise<AdminAgentDetail>;
91
+ /**
92
+ * How many of the org's skills each agent turns off, by agent id (agents turning none off are
93
+ * left out): the org's usable skills are resolved once per org, then matched against each
94
+ * agent's `disabledSkills` by the rule of `agentSkills` (a builtin plugin's skill and an org
95
+ * skill the agent shared are never off).
96
+ */
97
+ private skillsOff;
85
98
  /**
86
99
  * The org's live connectors by name, minus those the agent turns off as a whole: `tools: "all"`,
87
100
  * or a list naming every tool the connector has (a connector without tools stays listed).
@@ -12,8 +12,9 @@ import { sql } from "kysely";
12
12
  import { escapeLike } from "../conversations/conversations.service.js";
13
13
  import { ApiError } from "../errors.js";
14
14
  import { KernelDb } from "../infra/database/kernel-db.js";
15
- import { selectedSkills } from "../skills/usable.js";
15
+ import { agentSkills, builtinSkillIds, builtinSkillPlugins, linkedCopyIds, skillIdsOf, usableSkillVersions, } from "../skills/usable.js";
16
16
  import { AgentLookup } from "./agent-lookup.js";
17
+ import { skillDisabled, } from "./definition.js";
17
18
  const notFound = () => new ApiError("agent.not_found", "Agent not found");
18
19
  /**
19
20
  * Cross-org agent reads for the super admin (admin agents spec §3.2, §3.3): every org's live
@@ -41,7 +42,9 @@ let AdminAgents = class AdminAgents {
41
42
  .orderBy("agents.id")
42
43
  .limit(q.limit + 1)
43
44
  .execute();
44
- const page = rows.slice(0, q.limit).map(toRow);
45
+ const kept = rows.slice(0, q.limit);
46
+ const off = await this.skillsOff(kept);
47
+ const page = kept.map((r) => toRow(r, off.get(r.id) ?? 0));
45
48
  return { agents: page, next: rows.length > q.limit ? (page.at(-1)?.id ?? null) : null };
46
49
  }
47
50
  /** One live agent of a live org; otherwise `agent.not_found`. */
@@ -57,16 +60,17 @@ let AdminAgents = class AdminAgents {
57
60
  .where("agent_id", "=", agentId)
58
61
  .executeTakeFirstOrThrow(),
59
62
  ]);
60
- const [skills, connectors] = await Promise.all([
61
- selectedSkills(this.db.db, {
63
+ const [skills, off, connectors] = await Promise.all([
64
+ agentSkills(this.db.db, {
62
65
  orgId: row.org_id,
63
66
  agentId,
64
- orgSkills: view.definition.skills?.orgSkills ?? [],
67
+ disabledSkills: view.definition.disabledSkills ?? [],
65
68
  }),
69
+ this.skillsOff([row]),
66
70
  this.connectorsOf(row.org_id, view.definition.disabledTools),
67
71
  ]);
68
72
  return {
69
- ...toRow(row),
73
+ ...toRow(row, off.get(agentId) ?? 0),
70
74
  skills: skills
71
75
  .map((s) => ({ id: s.id, name: s.name, scope: s.scope }))
72
76
  .sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0)),
@@ -81,6 +85,58 @@ let AdminAgents = class AdminAgents {
81
85
  createdAt: view.createdAt,
82
86
  };
83
87
  }
88
+ /**
89
+ * How many of the org's skills each agent turns off, by agent id (agents turning none off are
90
+ * left out): the org's usable skills are resolved once per org, then matched against each
91
+ * agent's `disabledSkills` by the rule of `agentSkills` (a builtin plugin's skill and an org
92
+ * skill the agent shared are never off).
93
+ */
94
+ async skillsOff(rows) {
95
+ const out = new Map();
96
+ const byOrg = new Map();
97
+ for (const r of rows) {
98
+ const disabled = Array.isArray(r.disabled_skills)
99
+ ? r.disabled_skills
100
+ : [];
101
+ if (disabled.length === 0)
102
+ continue;
103
+ byOrg.set(r.org_id, [...(byOrg.get(r.org_id) ?? []), { id: r.id, disabled }]);
104
+ }
105
+ if (byOrg.size === 0)
106
+ return out;
107
+ const db = this.db.db;
108
+ const builtinPlugins = await builtinSkillPlugins(db);
109
+ const agentIds = [...byOrg.values()].flat().map((a) => a.id);
110
+ const sharedRows = await db
111
+ .selectFrom("skills")
112
+ .select(["id", "origin_agent_id"])
113
+ .where("scope", "=", "org")
114
+ .where("deleted_at", "is", null)
115
+ .where("origin_agent_id", "in", agentIds)
116
+ .execute();
117
+ const shared = new Map();
118
+ for (const r of sharedRows) {
119
+ const a = r.origin_agent_id;
120
+ shared.set(a, (shared.get(a) ?? new Set()).add(r.id));
121
+ }
122
+ for (const [orgId, agents] of byOrg) {
123
+ const usable = await usableSkillVersions(db, orgId);
124
+ const linked = await linkedCopyIds(db, orgId, usable.flatMap((r) => (r.origin === "platform" ? [r.id] : [])));
125
+ const builtinIds = new Set(await builtinSkillIds(db, orgId));
126
+ const candidates = usable.flatMap((r) => {
127
+ const ids = skillIdsOf(r, linked);
128
+ const fixed = (r.plugin !== null && builtinPlugins.has(r.plugin) && r.origin === "platform") ||
129
+ ids.some((id) => builtinIds.has(id));
130
+ return fixed ? [] : [{ plugin: r.plugin, name: r.name, ids }];
131
+ });
132
+ for (const a of agents) {
133
+ const mine = shared.get(a.id) ?? new Set();
134
+ const n = candidates.filter((c) => !c.ids.some((id) => mine.has(id)) && skillDisabled(a.disabled, c)).length;
135
+ out.set(a.id, n);
136
+ }
137
+ }
138
+ return out;
139
+ }
84
140
  /**
85
141
  * The org's live connectors by name, minus those the agent turns off as a whole: `tools: "all"`,
86
142
  * or a list naming every tool the connector has (a connector without tools stays listed).
@@ -132,6 +188,7 @@ let AdminAgents = class AdminAgents {
132
188
  "agents.org_id",
133
189
  "orgs.name as org_name",
134
190
  sql `agent_versions.definition->>'name'`.as("name"),
191
+ sql `agent_versions.definition->'disabledSkills'`.as("disabled_skills"),
135
192
  "agents.profile_avatar",
136
193
  "agents.owner_account_id",
137
194
  "accounts.display_name as owner_name",
@@ -151,7 +208,7 @@ AdminAgents = __decorate([
151
208
  __param(1, Inject(AgentLookup))
152
209
  ], AdminAgents);
153
210
  export { AdminAgents };
154
- function toRow(r) {
211
+ function toRow(r, skillsOff) {
155
212
  return {
156
213
  id: r.id,
157
214
  orgId: r.org_id,
@@ -165,6 +222,7 @@ function toRow(r) {
165
222
  createdFrom: r.created_from_template_id === null
166
223
  ? null
167
224
  : { templateId: r.created_from_template_id, name: r.created_from_template_name ?? null },
225
+ skillsOff,
168
226
  updatedAt: r.updated_at,
169
227
  };
170
228
  }
@@ -37,13 +37,19 @@ export declare const AgentCreateDefinition: z.ZodObject<{
37
37
  ask: "ask";
38
38
  deny: "deny";
39
39
  }>>>;
40
+ disabledSkills: z.ZodDefault<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
41
+ kind: z.ZodLiteral<"plugin">;
42
+ plugin: z.ZodString;
43
+ skills: z.ZodUnion<readonly [z.ZodLiteral<"all">, z.ZodArray<z.ZodString>]>;
44
+ }, z.core.$strict>, z.ZodObject<{
45
+ kind: z.ZodLiteral<"skill">;
46
+ skillId: z.ZodString;
47
+ }, z.core.$strict>], "kind">>>;
40
48
  skills: z.ZodOptional<z.ZodObject<{
41
- orgSkills: z.ZodDefault<z.ZodArray<z.ZodString>>;
42
49
  writePolicy: z.ZodOptional<z.ZodEnum<{
43
50
  allow: "allow";
44
51
  ask: "ask";
45
52
  }>>;
46
- pinned: z.ZodOptional<z.ZodArray<z.ZodString>>;
47
53
  }, z.core.$strict>>;
48
54
  subagents: z.ZodOptional<z.ZodObject<{
49
55
  general: z.ZodOptional<z.ZodBoolean>;
@@ -121,13 +127,19 @@ export declare const AgentCreateBody: z.ZodObject<{
121
127
  ask: "ask";
122
128
  deny: "deny";
123
129
  }>>>;
130
+ disabledSkills: z.ZodDefault<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
131
+ kind: z.ZodLiteral<"plugin">;
132
+ plugin: z.ZodString;
133
+ skills: z.ZodUnion<readonly [z.ZodLiteral<"all">, z.ZodArray<z.ZodString>]>;
134
+ }, z.core.$strict>, z.ZodObject<{
135
+ kind: z.ZodLiteral<"skill">;
136
+ skillId: z.ZodString;
137
+ }, z.core.$strict>], "kind">>>;
124
138
  skills: z.ZodOptional<z.ZodObject<{
125
- orgSkills: z.ZodDefault<z.ZodArray<z.ZodString>>;
126
139
  writePolicy: z.ZodOptional<z.ZodEnum<{
127
140
  allow: "allow";
128
141
  ask: "ask";
129
142
  }>>;
130
- pinned: z.ZodOptional<z.ZodArray<z.ZodString>>;
131
143
  }, z.core.$strict>>;
132
144
  subagents: z.ZodOptional<z.ZodObject<{
133
145
  general: z.ZodOptional<z.ZodBoolean>;
@@ -237,13 +249,19 @@ export declare const AgentUpdateBody: z.ZodObject<{
237
249
  ask: "ask";
238
250
  deny: "deny";
239
251
  }>>>;
252
+ disabledSkills: z.ZodDefault<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
253
+ kind: z.ZodLiteral<"plugin">;
254
+ plugin: z.ZodString;
255
+ skills: z.ZodUnion<readonly [z.ZodLiteral<"all">, z.ZodArray<z.ZodString>]>;
256
+ }, z.core.$strict>, z.ZodObject<{
257
+ kind: z.ZodLiteral<"skill">;
258
+ skillId: z.ZodString;
259
+ }, z.core.$strict>], "kind">>>;
240
260
  skills: z.ZodOptional<z.ZodObject<{
241
- orgSkills: z.ZodDefault<z.ZodArray<z.ZodString>>;
242
261
  writePolicy: z.ZodOptional<z.ZodEnum<{
243
262
  allow: "allow";
244
263
  ask: "ask";
245
264
  }>>;
246
- pinned: z.ZodOptional<z.ZodArray<z.ZodString>>;
247
265
  }, z.core.$strict>>;
248
266
  subagents: z.ZodOptional<z.ZodObject<{
249
267
  general: z.ZodOptional<z.ZodBoolean>;
@@ -40,7 +40,7 @@ export interface TemplateProvenance {
40
40
  name: string;
41
41
  }
42
42
  /** Why a `subagents` block is refused (`agent.subagents_invalid` details). */
43
- export type SubagentsProblem = "not_found" | "invalid_name" | "duplicate" | "tool_not_selected" | "skill_not_selected" | "agent_not_available" | "self" | "too_many";
43
+ export type SubagentsProblem = "not_found" | "invalid_name" | "duplicate" | "tool_not_selected" | "skill_not_available" | "agent_not_available" | "self" | "too_many";
44
44
  /**
45
45
  * Checks `subagents` of an agent definition in the caller's transaction (spec §5.2); throws 400
46
46
  * `agent.subagents_invalid` with one detail per problem (`{ reason, path, value? }`):
@@ -51,8 +51,9 @@ export type SubagentsProblem = "not_found" | "invalid_name" | "duplicate" | "too
51
51
  * bare template type equal to an inline name, a template typed `general-purpose`);
52
52
  * - `tool_not_selected`: an inline template's `tools`, `disallowedTools` or `toolPolicies` key that
53
53
  * is not a tool key of this agent (`toolKeys`, from `ToolRegistry.checkRefs`);
54
- * - `skill_not_selected`: an inline skill id that is neither in `skills.orgSkills` nor a live
55
- * skill of this agent;
54
+ * - `skill_not_available`: an inline skill id that is not one of this agent's skills (its own,
55
+ * the ones it shared, every skill on in the org its `disabledSkills` leaves on; skills default-on
56
+ * spec §4, §6.1);
56
57
  * - `self`: this agent allowlisted; `agent_not_available`: an allowlisted agent that is not a live
57
58
  * agent of the org visible to the person saving with `subagents.dispatchable: true` in its
58
59
  * current version;
@@ -22,11 +22,12 @@ import { OrgLock } from "../orgs/org-lock.js";
22
22
  import { can, roleAtLeast } from "../orgs/roles.js";
23
23
  import { ProviderRegistry } from "../runtime/providers.js";
24
24
  import { SkillChangesService } from "../skills/changes.service.js";
25
- import { assertOrgSkills, assertPinnedSkills } from "../skills/skills.service.js";
25
+ import { assertDisabledSkills } from "../skills/skills.service.js";
26
+ import { agentSkills } from "../skills/usable.js";
26
27
  import { legacyKeySaveText } from "../tools/legacy-keys.js";
27
28
  import { ToolRegistry } from "../tools/registry.js";
28
29
  import { AgentLookup, isAgentVisibleTo, visibleTo, } from "./agent-lookup.js";
29
- import { canonicalDisabledTools, normalizeStoredDefinition, paramIssues, SUBAGENT_NAME_RE, SUBAGENT_ROSTER_MAX, withoutRemovedBuiltinPolicies, } from "./definition.js";
30
+ import { canonicalDisabledSkills, canonicalDisabledTools, normalizeStoredDefinition, paramIssues, SUBAGENT_NAME_RE, SUBAGENT_ROSTER_MAX, withoutRemovedBuiltinPolicies, } from "./definition.js";
30
31
  import { deriveInstructions } from "./instruction-files.js";
31
32
  import { PendingConnectorRequests } from "./pending-connector-requests.js";
32
33
  import { randomPreset } from "./profile.js";
@@ -96,9 +97,16 @@ export function keepPendingConnectors(definition, given, current) {
96
97
  }
97
98
  return next.length > 0 ? { ...rest, pendingConnectors: [...next] } : rest;
98
99
  }
99
- /** `definition` with `disabledTools` in its canonical form (tools default-on spec §2). */
100
+ /**
101
+ * `definition` with `disabledTools` and `disabledSkills` in their canonical forms (tools default-on
102
+ * spec §2, skills default-on spec §4).
103
+ */
100
104
  function withCanonicalTools(definition) {
101
- return { ...definition, disabledTools: canonicalDisabledTools(definition.disabledTools ?? []) };
105
+ return {
106
+ ...definition,
107
+ disabledTools: canonicalDisabledTools(definition.disabledTools ?? []),
108
+ disabledSkills: canonicalDisabledSkills(definition.disabledSkills ?? []),
109
+ };
102
110
  }
103
111
  /**
104
112
  * Checks `subagents` of an agent definition in the caller's transaction (spec §5.2); throws 400
@@ -110,8 +118,9 @@ function withCanonicalTools(definition) {
110
118
  * bare template type equal to an inline name, a template typed `general-purpose`);
111
119
  * - `tool_not_selected`: an inline template's `tools`, `disallowedTools` or `toolPolicies` key that
112
120
  * is not a tool key of this agent (`toolKeys`, from `ToolRegistry.checkRefs`);
113
- * - `skill_not_selected`: an inline skill id that is neither in `skills.orgSkills` nor a live
114
- * skill of this agent;
121
+ * - `skill_not_available`: an inline skill id that is not one of this agent's skills (its own,
122
+ * the ones it shared, every skill on in the org its `disabledSkills` leaves on; skills default-on
123
+ * spec §4, §6.1);
115
124
  * - `self`: this agent allowlisted; `agent_not_available`: an allowlisted agent that is not a live
116
125
  * agent of the org visible to the person saving with `subagents.dispatchable: true` in its
117
126
  * current version;
@@ -189,19 +198,15 @@ export async function assertSubagents(t, a) {
189
198
  claim(type, path);
190
199
  });
191
200
  const inline = sub.inline ?? [];
192
- const selected = new Set(a.definition.skills?.orgSkills ?? []);
193
- const skillIds = [...new Set(inline.flatMap((x) => x.skills ?? []))].filter((id) => !selected.has(id));
194
- const own = a.agentId === null || skillIds.length === 0
201
+ const skillIds = [...new Set(inline.flatMap((x) => x.skills ?? []))];
202
+ // the agent's effective skills (an agent being created has no own or shared ones yet)
203
+ const available = skillIds.length === 0
195
204
  ? new Set()
196
- : new Set((await t
197
- .selectFrom("skills")
198
- .select("id")
199
- .where("org_id", "=", a.orgId)
200
- .where("scope", "=", "agent")
201
- .where("agent_id", "=", a.agentId)
202
- .where("deleted_at", "is", null)
203
- .where("id", "in", skillIds)
204
- .execute()).map((r) => r.id));
205
+ : new Set((await agentSkills(t, {
206
+ orgId: a.orgId,
207
+ agentId: a.agentId ?? "",
208
+ disabledSkills: a.definition.disabledSkills ?? [],
209
+ })).flatMap((r) => (r.platformSkillId !== undefined ? [r.id, r.platformSkillId] : [r.id])));
205
210
  inline.forEach((x, i) => {
206
211
  const base = `subagents.inline.${i}`;
207
212
  name(x.name, `${base}.name`);
@@ -222,8 +227,8 @@ export async function assertSubagents(t, a) {
222
227
  tool(key, `${base}.toolPolicies.${key}`);
223
228
  }
224
229
  (x.skills ?? []).forEach((id, j) => {
225
- if (!selected.has(id) && !own.has(id))
226
- add("skill_not_selected", `${base}.skills.${j}`, id);
230
+ if (!available.has(id))
231
+ add("skill_not_available", `${base}.skills.${j}`, id);
227
232
  });
228
233
  });
229
234
  const keptAgents = new Set((a.kept?.agents ?? []).map((x) => x.agentId));
@@ -424,6 +429,7 @@ let AgentsService = class AgentsService {
424
429
  const given = withoutRemovedBuiltinPolicies(request.definition);
425
430
  const input = {
426
431
  ...request,
432
+ givenDisabledSkills: given.disabledSkills ?? [],
427
433
  // run context spec §3.5: version 1 carries the description (the profile's when the
428
434
  // definition gives none)
429
435
  definition: withCanonicalTools(withDescription(deriveInstructions(given, null), given.description ?? request.profile?.description, undefined)),
@@ -445,8 +451,11 @@ let AgentsService = class AgentsService {
445
451
  if (template !== null && input.visibility !== "private" && !can(role, "agents.manage")) {
446
452
  throw new ApiError("agent.visibility_forbidden", "Only an organization admin can create an agent from a template for others; create it private");
447
453
  }
448
- await assertOrgSkills(t, orgId, input.definition.skills?.orgSkills ?? []);
449
- await assertPinnedSkills(t, orgId, null, input.definition.skills);
454
+ await assertDisabledSkills(t, {
455
+ orgId,
456
+ agentId: null,
457
+ disabled: input.givenDisabledSkills ?? input.definition.disabledSkills ?? [],
458
+ });
450
459
  await assertSubagents(t, {
451
460
  orgId,
452
461
  agentId: null,
@@ -604,10 +613,14 @@ let AgentsService = class AgentsService {
604
613
  .where("id", "=", agentId)
605
614
  .execute();
606
615
  }
607
- // 当前版本已有的技能引用保存时合法,不再核对(被删的技能不挡住其他改动);新加的照常核对
608
- const kept = new Set(current.definition.skills?.orgSkills ?? []);
609
- await assertOrgSkills(t, orgId, definition.skills?.orgSkills ?? [], kept);
610
- await assertPinnedSkills(t, orgId, agentId, definition.skills, current.definition.skills?.pinned ?? []);
616
+ // what the current version already turns off is not checked again (skills default-on §4)
617
+ await assertDisabledSkills(t, {
618
+ orgId,
619
+ agentId,
620
+ // as given, so `disabledSkills.<i>` names the caller's index; the canonical form is saved
621
+ disabled: patch.definition.disabledSkills ?? [],
622
+ kept: currentDefinition.disabledSkills ?? [],
623
+ });
611
624
  await assertSubagents(t, {
612
625
  orgId,
613
626
  agentId,
@@ -44,6 +44,36 @@ export declare const connectorToolDisabled: (disabled: readonly DisabledToolRef[
44
44
  * lists that turn off the same tools compare equal.
45
45
  */
46
46
  export declare function canonicalDisabledTools(disabled: readonly DisabledToolRef[]): DisabledToolRef[];
47
+ /**
48
+ * A skill an agent turns off (skills default-on spec §4): a plugin's skills by name, or `"all"` to
49
+ * turn the plugin off as a unit (skills it gains later included); a skill without a plugin (the
50
+ * org's own, shared or promoted ones) by id, since its name may change under the same id.
51
+ */
52
+ export declare const DisabledSkillRef: z.ZodDiscriminatedUnion<[z.ZodObject<{
53
+ kind: z.ZodLiteral<"plugin">;
54
+ plugin: z.ZodString;
55
+ skills: z.ZodUnion<readonly [z.ZodLiteral<"all">, z.ZodArray<z.ZodString>]>;
56
+ }, z.core.$strict>, z.ZodObject<{
57
+ kind: z.ZodLiteral<"skill">;
58
+ skillId: z.ZodString;
59
+ }, z.core.$strict>], "kind">;
60
+ export type DisabledSkillRef = z.output<typeof DisabledSkillRef>;
61
+ /**
62
+ * Is a skill turned off by `disabled`? `plugin` and `name` match a plugin entry; `ids` (the
63
+ * skill's id and, for a linked or promoted copy, the platform skill it serves) a skill entry.
64
+ */
65
+ export declare function skillDisabled(disabled: readonly DisabledSkillRef[] | undefined, skill: {
66
+ plugin: string | null;
67
+ name: string;
68
+ ids: readonly string[];
69
+ }): boolean;
70
+ /**
71
+ * `disabled` in its canonical form: one entry per plugin (sorted by plugin, `"all"` absorbing
72
+ * names, names deduplicated and sorted, an empty list dropped), then the skill entries deduplicated
73
+ * and sorted by id. Saving stores this form, so two lists that turn off the same skills compare
74
+ * equal.
75
+ */
76
+ export declare function canonicalDisabledSkills(disabled: readonly DisabledSkillRef[]): DisabledSkillRef[];
47
77
  /**
48
78
  * A sub-agent's tool filter by tool key (tools default-on spec §4): written only into a child's
49
79
  * effective definition at dispatch (never accepted on save). `deny` removes keys (the child-removed
@@ -60,8 +90,8 @@ export type SubagentTools = z.infer<typeof SubagentToolsSchema>;
60
90
  export declare const SUBAGENT_NAME_RE: RegExp;
61
91
  /**
62
92
  * A sub-agent template written in the agent definition (phase C, spec §5.2): the fields of a
63
- * plugin agent template (`AgentTemplate`, spec §16.1), with `skills` as skill ids (org skills the
64
- * agent selects, or the agent's own) instead of names. Names and selections are checked on save
93
+ * plugin agent template (`AgentTemplate`, spec §16.1), with `skills` as skill ids (skills the agent
94
+ * has, skills default-on spec §6.1) instead of names. Names and skills are checked on save
65
95
  * (`agent.subagents_invalid`); the schema only bounds the input.
66
96
  */
67
97
  export declare const InlineAgentTemplate: z.ZodObject<{
@@ -200,13 +230,19 @@ export declare const AgentDefinitionSchema: z.ZodObject<{
200
230
  ask: "ask";
201
231
  deny: "deny";
202
232
  }>>>;
233
+ disabledSkills: z.ZodDefault<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
234
+ kind: z.ZodLiteral<"plugin">;
235
+ plugin: z.ZodString;
236
+ skills: z.ZodUnion<readonly [z.ZodLiteral<"all">, z.ZodArray<z.ZodString>]>;
237
+ }, z.core.$strict>, z.ZodObject<{
238
+ kind: z.ZodLiteral<"skill">;
239
+ skillId: z.ZodString;
240
+ }, z.core.$strict>], "kind">>>;
203
241
  skills: z.ZodOptional<z.ZodObject<{
204
- orgSkills: z.ZodDefault<z.ZodArray<z.ZodString>>;
205
242
  writePolicy: z.ZodOptional<z.ZodEnum<{
206
243
  allow: "allow";
207
244
  ask: "ask";
208
245
  }>>;
209
- pinned: z.ZodOptional<z.ZodArray<z.ZodString>>;
210
246
  }, z.core.$strict>>;
211
247
  subagents: z.ZodOptional<z.ZodObject<{
212
248
  general: z.ZodOptional<z.ZodBoolean>;
@@ -313,8 +349,10 @@ export declare function needsLegacyScope(definition: unknown): boolean;
313
349
  * current keys ({@link normalizeToolKeys}: builtins always, `<x>__<tool>` keys with `scope`), and
314
350
  * a definition from before tools were on by default (an enabled `tools` list, history only: the
315
351
  * migration rewrote stored versions) reads as nothing turned off, which is what the migration
316
- * writes (tools default-on spec §2, §3). Other fields are kept; without old forms the same object
317
- * is returned.
352
+ * writes (tools default-on spec §2, §3). Likewise a definition from before skills were on by
353
+ * default (`skills.orgSkills` / `skills.pinned`) reads as no skill turned off (skills default-on
354
+ * spec §4; migration 0116 rewrote stored versions). Other fields are kept; without old forms the
355
+ * same object is returned.
318
356
  */
319
357
  export declare function normalizeStoredDefinition(def: unknown, scope?: LegacyScope): AgentDefinition;
320
358
  /** 按模型声明严格校验一组参数,返回 `{ path: "<field>.<key>", message }[]`(评测候选也用它)。 */
@@ -66,6 +66,69 @@ export function canonicalDisabledTools(disabled) {
66
66
  }
67
67
  return out;
68
68
  }
69
+ /**
70
+ * A skill an agent turns off (skills default-on spec §4): a plugin's skills by name, or `"all"` to
71
+ * turn the plugin off as a unit (skills it gains later included); a skill without a plugin (the
72
+ * org's own, shared or promoted ones) by id, since its name may change under the same id.
73
+ */
74
+ export const DisabledSkillRef = z.discriminatedUnion("kind", [
75
+ z
76
+ .object({
77
+ kind: z.literal("plugin"),
78
+ plugin: z.string().min(1).max(200),
79
+ skills: z.union([z.literal("all"), z.array(z.string().min(1).max(64)).min(1).max(500)]),
80
+ })
81
+ .strict(),
82
+ z.object({ kind: z.literal("skill"), skillId: z.string().min(1).max(100) }).strict(),
83
+ ]);
84
+ /**
85
+ * Is a skill turned off by `disabled`? `plugin` and `name` match a plugin entry; `ids` (the
86
+ * skill's id and, for a linked or promoted copy, the platform skill it serves) a skill entry.
87
+ */
88
+ export function skillDisabled(disabled, skill) {
89
+ return (disabled ?? []).some((r) => r.kind === "plugin"
90
+ ? skill.plugin !== null &&
91
+ r.plugin === skill.plugin &&
92
+ (r.skills === "all" || r.skills.includes(skill.name))
93
+ : skill.ids.includes(r.skillId));
94
+ }
95
+ /**
96
+ * `disabled` in its canonical form: one entry per plugin (sorted by plugin, `"all"` absorbing
97
+ * names, names deduplicated and sorted, an empty list dropped), then the skill entries deduplicated
98
+ * and sorted by id. Saving stores this form, so two lists that turn off the same skills compare
99
+ * equal.
100
+ */
101
+ export function canonicalDisabledSkills(disabled) {
102
+ const plugins = [];
103
+ const ids = new Set();
104
+ for (const r of disabled) {
105
+ if (r.kind === "skill") {
106
+ ids.add(r.skillId);
107
+ continue;
108
+ }
109
+ const names = r.skills;
110
+ const prev = plugins.find((x) => x.plugin === r.plugin);
111
+ if (prev) {
112
+ prev.skills =
113
+ prev.skills === "all" || names === "all"
114
+ ? "all"
115
+ : [...new Set([...prev.skills, ...names])].sort();
116
+ }
117
+ else {
118
+ plugins.push({
119
+ kind: "plugin",
120
+ plugin: r.plugin,
121
+ skills: names === "all" ? "all" : [...new Set(names)].sort(),
122
+ });
123
+ }
124
+ }
125
+ return [
126
+ ...plugins
127
+ .filter((p) => p.skills === "all" || p.skills.length > 0)
128
+ .sort((a, b) => (a.plugin < b.plugin ? -1 : a.plugin > b.plugin ? 1 : 0)),
129
+ ...[...ids].sort().map((skillId) => ({ kind: "skill", skillId })),
130
+ ];
131
+ }
69
132
  /**
70
133
  * A sub-agent's tool filter by tool key (tools default-on spec §4): written only into a child's
71
134
  * effective definition at dispatch (never accepted on save). `deny` removes keys (the child-removed
@@ -83,8 +146,8 @@ export const SubagentToolsSchema = z
83
146
  export const SUBAGENT_NAME_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;
84
147
  /**
85
148
  * A sub-agent template written in the agent definition (phase C, spec §5.2): the fields of a
86
- * plugin agent template (`AgentTemplate`, spec §16.1), with `skills` as skill ids (org skills the
87
- * agent selects, or the agent's own) instead of names. Names and selections are checked on save
149
+ * plugin agent template (`AgentTemplate`, spec §16.1), with `skills` as skill ids (skills the agent
150
+ * has, skills default-on spec §6.1) instead of names. Names and skills are checked on save
88
151
  * (`agent.subagents_invalid`); the schema only bounds the input.
89
152
  */
90
153
  export const InlineAgentTemplate = z
@@ -217,25 +280,19 @@ export const AgentDefinitionSchema = z.object({
217
280
  */
218
281
  toolPolicies: z.record(z.string(), z.enum(["allow", "ask", "deny"])).default({}),
219
282
  /**
220
- * 技能(M5 T13):`orgSkills` 是引用的组织技能 id(保存时校验属于本组织且未删除,不可重复)。
221
- * agent 自己的技能(`scope=agent`)自动对它生效,不进定义。可省略(较早保存的定义也没有),按空处理;
222
- * 不给默认值:没用技能的定义保存前后不变,不会因此多出一个版本。
283
+ * The skills this agent turns off (skills default-on spec §4); every other skill on in the org
284
+ * is on for it, and its own and shared skills always are. Saved in canonical form
285
+ * ({@link canonicalDisabledSkills}); checked on save.
286
+ */
287
+ disabledSkills: z.array(DisabledSkillRef).max(500).default([]),
288
+ /**
223
289
  * `writePolicy`: whether registering a skill on a private agent (`agents.register-skill`) needs
224
- * the person's confirmation; absent means `allow` (not stored in the definition). On a shared
225
- * agent a registration is always confirmed at the org level.
290
+ * the person's confirmation; absent means `allow`. On a shared agent a registration is always
291
+ * confirmed at the org level. No default: definitions without it gain no version.
226
292
  */
227
293
  skills: z
228
294
  .object({
229
- orgSkills: z.array(z.string().min(1).max(100)).max(100).default([]),
230
295
  writePolicy: z.enum(["allow", "ask"]).optional(),
231
- /**
232
- * Pinned skills (phase B, spec §9.1): ids of selected org skills or of the agent's own
233
- * skills, whose bodies apply throughout every conversation, in this order. At most
234
- * `PINNED_SKILLS_LIMITS.count` (checked with the other rules by `assertPinnedSkills`, as
235
- * `agent.pinned_invalid`; the schema only bounds the input). No default: definitions
236
- * without it are unchanged.
237
- */
238
- pinned: z.array(z.string().min(1).max(100)).max(100).optional(),
239
296
  })
240
297
  .strict()
241
298
  .optional(),
@@ -478,8 +535,10 @@ function normalizeToolRef(v) {
478
535
  * current keys ({@link normalizeToolKeys}: builtins always, `<x>__<tool>` keys with `scope`), and
479
536
  * a definition from before tools were on by default (an enabled `tools` list, history only: the
480
537
  * migration rewrote stored versions) reads as nothing turned off, which is what the migration
481
- * writes (tools default-on spec §2, §3). Other fields are kept; without old forms the same object
482
- * is returned.
538
+ * writes (tools default-on spec §2, §3). Likewise a definition from before skills were on by
539
+ * default (`skills.orgSkills` / `skills.pinned`) reads as no skill turned off (skills default-on
540
+ * spec §4; migration 0116 rewrote stored versions). Other fields are kept; without old forms the
541
+ * same object is returned.
483
542
  */
484
543
  export function normalizeStoredDefinition(def, scope) {
485
544
  let d = def;
@@ -495,6 +554,15 @@ export function normalizeStoredDefinition(def, scope) {
495
554
  else if (!Array.isArray(d.disabledTools)) {
496
555
  d = { ...d, disabledTools: [] };
497
556
  }
557
+ // before skills were on by default (skills default-on spec §4, §5): selected and pinned skills
558
+ // read as nothing turned off, which is what migration 0116 writes
559
+ if (isRecord(d.skills) && ("orgSkills" in d.skills || "pinned" in d.skills)) {
560
+ const { orgSkills: _o, pinned: _p, ...keep } = d.skills;
561
+ const { skills: _s, ...rest } = d;
562
+ d = Object.keys(keep).length > 0 ? { ...rest, skills: keep } : rest;
563
+ }
564
+ if (!Array.isArray(d.disabledSkills))
565
+ d = { ...d, disabledSkills: [] };
498
566
  return d;
499
567
  }
500
568
  /** 按模型声明严格校验一组参数,返回 `{ path: "<field>.<key>", message }[]`(评测候选也用它)。 */