@capybara-hq/kernel 0.1.0-rc.21 → 0.1.0-rc.23
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.
- package/dist/admin/admin.controller.d.ts +3 -3
- package/dist/admin/admin.controller.js +6 -2
- package/dist/admin/admin.schemas.d.ts +13 -0
- package/dist/agents/admin-agents.d.ts +16 -3
- package/dist/agents/admin-agents.js +65 -7
- package/dist/agents/agents.schemas.d.ts +24 -6
- package/dist/agents/agents.service.d.ts +4 -3
- package/dist/agents/agents.service.js +39 -26
- package/dist/agents/definition.d.ts +44 -6
- package/dist/agents/definition.js +86 -18
- package/dist/agents/from-template.d.ts +6 -3
- package/dist/agents/from-template.js +57 -44
- package/dist/agents/org-templates.js +97 -41
- package/dist/agents/templates.d.ts +6 -0
- package/dist/agents/templates.js +15 -1
- package/dist/background/launch.d.ts +43 -5
- package/dist/background/launch.js +88 -8
- package/dist/background/session.d.ts +14 -2
- package/dist/background/session.js +26 -4
- package/dist/background/status.d.ts +1 -1
- package/dist/background/status.js +3 -3
- package/dist/background/stop.d.ts +0 -2
- package/dist/background/stop.js +1 -21
- package/dist/catalog/admin-catalog.controller.d.ts +2 -4
- package/dist/catalog/admin-catalog.controller.js +2 -6
- package/dist/catalog/catalog-content.d.ts +5 -0
- package/dist/catalog/catalog-content.js +1 -0
- package/dist/catalog/catalog.module.js +3 -0
- package/dist/catalog/claude/report.d.ts +9 -2
- package/dist/catalog/claude/report.js +1 -0
- package/dist/catalog/claude/translate.js +1 -1
- package/dist/catalog/component-promotion.js +1 -2
- package/dist/catalog/component-state.d.ts +13 -1
- package/dist/catalog/component-state.js +14 -5
- package/dist/catalog/marketplaces.service.d.ts +1 -1
- package/dist/catalog/marketplaces.service.js +2 -1
- package/dist/catalog/org-catalog.controller.d.ts +13 -3
- package/dist/catalog/org-catalog.controller.js +26 -4
- package/dist/catalog/org-catalog.schemas.d.ts +13 -0
- package/dist/catalog/org-catalog.schemas.js +34 -0
- package/dist/catalog/org-plugin-uploads.controller.js +0 -1
- package/dist/catalog/org-plugin-uploads.d.ts +0 -1
- package/dist/catalog/org-plugin-uploads.js +0 -3
- package/dist/catalog/org-plugin-uploads.schemas.d.ts +0 -1
- package/dist/catalog/org-plugin-uploads.schemas.js +0 -2
- package/dist/catalog/platform-components.d.ts +0 -1
- package/dist/catalog/platform-components.js +3 -8
- package/dist/catalog/plugin-import.d.ts +0 -8
- package/dist/catalog/plugin-import.js +4 -35
- package/dist/catalog/plugin-install.d.ts +2 -2
- package/dist/catalog/plugin-install.js +2 -2
- package/dist/catalog/plugin-package.d.ts +7 -0
- package/dist/catalog/plugin-package.js +27 -1
- package/dist/catalog/plugin-upgrade.d.ts +5 -6
- package/dist/catalog/plugin-upgrade.js +5 -23
- package/dist/catalog/requests.service.d.ts +66 -10
- package/dist/catalog/requests.service.js +196 -15
- package/dist/channels/actions.d.ts +2 -0
- package/dist/channels/actions.js +19 -4
- package/dist/channels/cards.d.ts +16 -2
- package/dist/channels/cards.js +40 -7
- package/dist/channels/channels.module.js +3 -0
- package/dist/channels/outbound.d.ts +22 -1
- package/dist/channels/outbound.js +116 -7
- package/dist/channels/phrases.d.ts +25 -0
- package/dist/channels/phrases.js +19 -0
- package/dist/channels/threads.d.ts +12 -0
- package/dist/channels/threads.js +34 -0
- package/dist/config/schema.d.ts +23 -1
- package/dist/config/schema.js +107 -5
- package/dist/conversations/conversations.service.d.ts +42 -9
- package/dist/conversations/conversations.service.js +57 -25
- package/dist/conversations/events.d.ts +106 -11
- package/dist/conversations/events.js +121 -18
- package/dist/conversations/message-context.d.ts +6 -3
- package/dist/conversations/message-context.js +14 -10
- package/dist/conversations/queue.d.ts +15 -2
- package/dist/conversations/queue.js +22 -3
- package/dist/conversations/queue.service.d.ts +12 -6
- package/dist/conversations/queue.service.js +36 -13
- package/dist/db/kernel-schema.d.ts +105 -3
- package/dist/devices/conversation-devices.d.ts +8 -1
- package/dist/devices/conversation-devices.js +8 -0
- package/dist/devices/devices.controller.d.ts +21 -4
- package/dist/devices/devices.controller.js +46 -8
- package/dist/devices/devices.schemas.d.ts +9 -1
- package/dist/devices/devices.schemas.js +11 -3
- package/dist/devices/devices.service.d.ts +176 -4
- package/dist/devices/devices.service.js +347 -6
- package/dist/devices/dto.d.ts +56 -3
- package/dist/devices/dto.js +51 -1
- package/dist/devices/public-suffix.d.ts +6 -0
- package/dist/devices/public-suffix.js +79 -0
- package/dist/errors.d.ts +50 -5
- package/dist/errors.js +50 -5
- package/dist/evals/reconstruct.d.ts +18 -13
- package/dist/evals/reconstruct.js +50 -36
- package/dist/evals/recorded-tools.d.ts +7 -7
- package/dist/evals/recorded-tools.js +4 -3
- package/dist/evals/trajectory.d.ts +6 -1
- package/dist/evals/trajectory.js +7 -0
- package/dist/extensions/package.js +2 -2
- package/dist/http/api.module.js +5 -0
- package/dist/identity/settings.d.ts +53 -3
- package/dist/identity/settings.js +92 -9
- package/dist/inbox/inbox.module.js +2 -1
- package/dist/inbox/inbox.service.d.ts +19 -4
- package/dist/inbox/inbox.service.js +14 -3
- package/dist/infra/config/kernel-config.service.d.ts +7 -0
- package/dist/infra/config/kernel-config.service.js +31 -0
- package/dist/infra/events/kernel-events.d.ts +2 -1
- package/dist/local-devices/device-policy.service.d.ts +65 -0
- package/dist/local-devices/device-policy.service.js +217 -0
- package/dist/local-devices/local-device-gateway.d.ts +4 -2
- package/dist/local-devices/local-device-gateway.js +39 -11
- package/dist/local-devices/local-device-provider.d.ts +40 -3
- package/dist/local-devices/local-device-provider.js +109 -7
- package/dist/local-devices/local-devices.module.d.ts +2 -1
- package/dist/local-devices/local-devices.module.js +19 -3
- package/dist/local-devices/machines.d.ts +30 -3
- package/dist/local-devices/machines.js +79 -3
- package/dist/local-devices/network-grants.d.ts +104 -0
- package/dist/local-devices/network-grants.js +288 -0
- package/dist/local-devices/policy-summary.d.ts +20 -0
- package/dist/local-devices/policy-summary.js +63 -0
- package/dist/orgs/orgs.module.js +4 -10
- package/dist/orgs/roles.d.ts +1 -1
- package/dist/orgs/roles.js +4 -0
- package/dist/orgs/settings.controller.js +4 -3
- package/dist/orgs/settings.service.d.ts +172 -14
- package/dist/orgs/settings.service.js +229 -27
- package/dist/platform/exclusions.js +11 -1
- package/dist/platform/operation.js +4 -0
- package/dist/platform/ops/admin-items.ops.js +1 -1
- package/dist/platform/ops/admin.ops.js +32 -7
- package/dist/platform/ops/agent-skills.ops.js +2 -2
- package/dist/platform/ops/agent-templates.ops.js +2 -2
- package/dist/platform/ops/agents.ops.js +11 -15
- package/dist/platform/ops/devices.ops.js +3 -1
- package/dist/platform/ops/inbox.ops.js +19 -0
- package/dist/platform/ops/org-settings.ops.js +15 -6
- package/dist/platform/ops/orgs.ops.js +1 -0
- package/dist/platform/ops/platform.ops.d.ts +9 -1
- package/dist/platform/ops/platform.ops.js +34 -12
- package/dist/platform/ops/requests.ops.js +3 -2
- package/dist/platform/ops/schedules.ops.d.ts +21 -0
- package/dist/platform/ops/schedules.ops.js +470 -0
- package/dist/platform/ops/skills.ops.js +3 -3
- package/dist/platform/platform-ops.module.d.ts +2 -1
- package/dist/platform/platform-ops.module.js +5 -0
- package/dist/platform/route-schemas.js +3 -0
- package/dist/roles/worker.module.js +3 -0
- package/dist/runtime/context/build.js +13 -4
- package/dist/runtime/context/compaction.js +6 -3
- package/dist/runtime/context/device-paths.d.ts +43 -21
- package/dist/runtime/context/device-paths.js +104 -21
- package/dist/runtime/context/run-context.d.ts +9 -0
- package/dist/runtime/context/run-context.js +8 -0
- package/dist/runtime/context/skills.d.ts +14 -1
- package/dist/runtime/context/skills.js +36 -5
- package/dist/runtime/maintenance.d.ts +4 -2
- package/dist/runtime/maintenance.js +16 -5
- package/dist/runtime/run-finish.d.ts +6 -1
- package/dist/runtime/run-finish.js +16 -2
- package/dist/runtime/run-queue.js +21 -2
- package/dist/runtime/run-worker.js +14 -33
- package/dist/runtime/runtime.module.js +3 -0
- package/dist/runtime/subagents/definition.d.ts +32 -14
- package/dist/runtime/subagents/definition.js +106 -109
- package/dist/runtime/subagents/dispatch.js +4 -3
- package/dist/runtime/subagents/preamble.d.ts +2 -1
- package/dist/runtime/subagents/preamble.js +2 -1
- package/dist/runtime/waits.js +14 -4
- package/dist/sandbox/platform-tiers.d.ts +86 -0
- package/dist/sandbox/platform-tiers.js +97 -0
- package/dist/sandbox/sandbox.service.d.ts +121 -11
- package/dist/sandbox/sandbox.service.js +351 -30
- package/dist/sandbox/tiers.d.ts +98 -0
- package/dist/sandbox/tiers.js +104 -0
- package/dist/schedules/effective-settings.d.ts +16 -0
- package/dist/schedules/effective-settings.js +17 -0
- package/dist/schedules/errors.d.ts +8 -0
- package/dist/schedules/errors.js +8 -0
- package/dist/schedules/fire.d.ts +118 -0
- package/dist/schedules/fire.js +625 -0
- package/dist/schedules/grant-rules.d.ts +94 -0
- package/dist/schedules/grant-rules.js +126 -0
- package/dist/schedules/job-ids.d.ts +32 -0
- package/dist/schedules/job-ids.js +27 -0
- package/dist/schedules/pause.d.ts +9 -0
- package/dist/schedules/pause.js +33 -0
- package/dist/schedules/run-tracker.d.ts +81 -0
- package/dist/schedules/run-tracker.js +333 -0
- package/dist/schedules/scan.job.d.ts +64 -0
- package/dist/schedules/scan.job.js +303 -0
- package/dist/schedules/schedule-math.d.ts +31 -0
- package/dist/schedules/schedule-math.js +223 -0
- package/dist/schedules/scheduled-tasks.service.d.ts +351 -0
- package/dist/schedules/scheduled-tasks.service.js +1193 -0
- package/dist/schedules/schedules.controller.d.ts +68 -0
- package/dist/schedules/schedules.controller.js +242 -0
- package/dist/schedules/schedules.module.d.ts +16 -0
- package/dist/schedules/schedules.module.js +65 -0
- package/dist/schedules/schedules.schemas.d.ts +316 -0
- package/dist/schedules/schedules.schemas.js +186 -0
- package/dist/schedules/store.d.ts +81 -0
- package/dist/schedules/store.js +390 -0
- package/dist/schedules/store.module.d.ts +6 -0
- package/dist/schedules/store.module.js +21 -0
- package/dist/schedules/types.d.ts +108 -0
- package/dist/schedules/types.js +1 -0
- package/dist/schedules/unattended.d.ts +117 -0
- package/dist/schedules/unattended.js +228 -0
- package/dist/setup/oauth-token-probe.js +8 -4
- package/dist/skills/agent-skills.service.d.ts +4 -8
- package/dist/skills/agent-skills.service.js +18 -53
- package/dist/skills/catalog.d.ts +65 -62
- package/dist/skills/catalog.js +109 -206
- package/dist/skills/conversation-catalog.d.ts +3 -3
- package/dist/skills/conversation-catalog.js +5 -12
- package/dist/skills/invoke.d.ts +2 -2
- package/dist/skills/skills.controller.d.ts +3 -1
- package/dist/skills/skills.service.d.ts +38 -37
- package/dist/skills/skills.service.js +168 -107
- package/dist/skills/usable.d.ts +57 -8
- package/dist/skills/usable.js +172 -38
- package/dist/tools/approvals.controller.d.ts +4 -2
- package/dist/tools/approvals.controller.js +17 -2
- package/dist/tools/approvals.schemas.d.ts +1 -0
- package/dist/tools/approvals.schemas.js +3 -1
- package/dist/tools/approvals.service.d.ts +182 -7
- package/dist/tools/approvals.service.js +597 -13
- package/dist/tools/builtin-names.d.ts +25 -4
- package/dist/tools/builtin-names.js +45 -4
- package/dist/tools/builtins/builtin-tools.d.ts +8 -0
- package/dist/tools/builtins/builtin-tools.js +23 -2
- package/dist/tools/builtins/sandbox/bash.js +16 -7
- package/dist/tools/builtins/sandbox/common.d.ts +1 -1
- package/dist/tools/builtins/sandbox/common.js +33 -10
- package/dist/tools/builtins/sandbox/edit.js +7 -3
- package/dist/tools/builtins/sandbox/file-state.d.ts +31 -1
- package/dist/tools/builtins/sandbox/file-state.js +33 -3
- package/dist/tools/builtins/sandbox/write.js +8 -4
- package/dist/tools/builtins/schedules.d.ts +107 -0
- package/dist/tools/builtins/schedules.js +789 -0
- package/dist/tools/elicitation.d.ts +2 -0
- package/dist/tools/elicitation.js +1 -1
- package/dist/tools/fixed-ask.d.ts +7 -0
- package/dist/tools/fixed-ask.js +9 -0
- package/dist/tools/network-asks.d.ts +109 -0
- package/dist/tools/network-asks.js +221 -0
- package/dist/tools/pipeline.d.ts +53 -6
- package/dist/tools/pipeline.js +202 -13
- package/dist/tools/policy.d.ts +21 -8
- package/dist/tools/policy.js +63 -9
- package/dist/tools/registry.d.ts +10 -1
- package/dist/tools/tools.module.js +12 -0
- package/package.json +2 -2
- package/src/migrations/0113_scheduled_tasks.sql +108 -0
- package/src/migrations/0114_network_asks.sql +23 -0
- package/src/migrations/0115_network_requests.sql +28 -0
- package/src/migrations/0116_skills_default_on.sql +37 -0
- 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
|
|
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
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
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
|
|
139
|
-
const
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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
|
|
158
|
-
message: `Skill ${
|
|
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
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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 (
|
|
233
|
-
|
|
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("
|
|
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
|
|
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
|
-
|
|
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) => ({
|
|
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")
|
package/dist/skills/usable.d.ts
CHANGED
|
@@ -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?:
|
|
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
|
|
63
|
-
* it shared
|
|
64
|
-
*
|
|
65
|
-
* platform skills
|
|
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
|
|
115
|
+
export declare function agentSkills(db: KernelSchemaDb, a: {
|
|
68
116
|
orgId: string;
|
|
69
117
|
agentId: string;
|
|
70
|
-
|
|
71
|
-
}, log?:
|
|
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 {};
|