@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.
- 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/catalog/admin-catalog.controller.d.ts +2 -4
- package/dist/catalog/admin-catalog.controller.js +2 -6
- 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 +105 -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 +341 -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 +46 -5
- package/dist/errors.js +46 -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/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.js +11 -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.js +4 -1
- 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 +14 -3
- package/dist/local-devices/machines.js +41 -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 +2 -1
- package/dist/orgs/settings.service.d.ts +164 -12
- package/dist/orgs/settings.service.js +212 -24
- 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/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 +14 -5
- 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/sandbox.service.d.ts +120 -10
- package/dist/sandbox/sandbox.service.js +335 -28
- package/dist/sandbox/tiers.d.ts +86 -0
- package/dist/sandbox/tiers.js +96 -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
package/dist/skills/catalog.js
CHANGED
|
@@ -7,38 +7,28 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
8
8
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
9
9
|
};
|
|
10
|
-
import { createHash } from "node:crypto";
|
|
11
|
-
import { parseSkillMd, SKILL_ENTRY_FILE, } from "@capybara-hq/plugin-sdk";
|
|
12
10
|
import { Inject, Injectable } from "@nestjs/common";
|
|
13
11
|
import { sql } from "kysely";
|
|
14
12
|
import { EventLog } from "../conversations/event-log.js";
|
|
15
13
|
import { SKILLS_CATALOG_MAX } from "../conversations/events.js";
|
|
16
|
-
import {
|
|
14
|
+
import { KernelConfigService } from "../infra/config/kernel-config.service.js";
|
|
17
15
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
18
16
|
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
19
17
|
import { Transactional } from "../infra/database/transactional.decorator.js";
|
|
20
18
|
import { KERNEL_LOGGER } from "../infra/tokens.js";
|
|
21
19
|
import { CLAUDE_CODE_TOOL_MAP } from "../runtime/context/claude-tools.js";
|
|
22
|
-
import { sameSnapshot, } from "../runtime/context/skills.js";
|
|
23
|
-
import {
|
|
24
|
-
import { selectedSkills, skillFileStore } from "./usable.js";
|
|
20
|
+
import { catalogLine, sameSnapshot, } from "../runtime/context/skills.js";
|
|
21
|
+
import { agentOwnSkillIds, agentSkills, builtinSkillIds, builtinSkillPlugins, } from "./usable.js";
|
|
25
22
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* the
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* 此刻对这个对话生效的技能,按名字(码点序)排序:
|
|
37
|
-
* - 运行所用 agent 版本选中的组织技能(`scope='org'`,id 在 `skills.orgSkills` 里);
|
|
38
|
-
* - 加上这个 agent 自己的技能(`scope='agent'`);
|
|
39
|
-
* - 已删除的跳过(保存过的 agent 版本仍可能引用它们);
|
|
40
|
-
* - 版本取 `current_version`,描述取该版本清单里的描述。
|
|
41
|
-
* 组织技能与 agent 自己的技能同名时只保留 agent 自己的(更具体;`/skills/<name>/` 与按名字加载都不能有两个)。
|
|
23
|
+
* The skills in effect for this conversation now, sorted by name (code point order), as
|
|
24
|
+
* {@link agentSkills} resolves them (skills default-on spec §3):
|
|
25
|
+
* - the agent's own skills (`scope='agent'`) and the org skills it shared;
|
|
26
|
+
* - plus every skill on in the org, minus what the run's agent version's `disabledSkills` turns
|
|
27
|
+
* off (never a builtin plugin's skill);
|
|
28
|
+
* - deleted skills are skipped;
|
|
29
|
+
* - the version is `current_version`, the description the one in that version's manifest.
|
|
30
|
+
* When an org skill and the agent's own skill share a name only the agent's own is kept (more
|
|
31
|
+
* specific; neither `/skills/<name>/` nor loading by name can have two).
|
|
42
32
|
*
|
|
43
33
|
* Trials: a pending version proposal of this agent made in this conversation replaces, by name,
|
|
44
34
|
* the version of its skill (the id of the existing skill, the version it would become on
|
|
@@ -77,12 +67,13 @@ function forModel(all, input, log) {
|
|
|
77
67
|
* `conversationId` (a conversation not created yet) no trial draft applies.
|
|
78
68
|
*/
|
|
79
69
|
export async function resolveSkills(db, input, log) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
//
|
|
70
|
+
const rows = await agentSkills(db, {
|
|
71
|
+
orgId: input.orgId,
|
|
72
|
+
agentId: input.agentId,
|
|
73
|
+
disabledSkills: input.agent.disabledSkills ?? [],
|
|
74
|
+
}, log);
|
|
75
|
+
// One skill per name: the agent's own, then an org skill or copy, then a platform skill; ties by
|
|
76
|
+
// id
|
|
86
77
|
const rank = (r) => r.scope === "agent" ? 0 : r.platformSkillId === r.id ? 2 : 1;
|
|
87
78
|
const byName = new Map();
|
|
88
79
|
for (const r of rows) {
|
|
@@ -103,6 +94,8 @@ export async function resolveSkills(db, input, log) {
|
|
|
103
94
|
},
|
|
104
95
|
format: r.format,
|
|
105
96
|
manifest: r.manifest,
|
|
97
|
+
scope: r.scope,
|
|
98
|
+
origin: r.origin,
|
|
106
99
|
},
|
|
107
100
|
]));
|
|
108
101
|
const trials = input.conversationId === undefined
|
|
@@ -118,6 +111,7 @@ export async function resolveSkills(db, input, log) {
|
|
|
118
111
|
.where("kind", "=", "version")
|
|
119
112
|
.execute();
|
|
120
113
|
for (const { proposed_version: p, object_prefix } of trials) {
|
|
114
|
+
const replaced = effective.get(p.manifest.name);
|
|
121
115
|
effective.set(p.manifest.name, {
|
|
122
116
|
skill: {
|
|
123
117
|
id: p.skillId,
|
|
@@ -128,160 +122,61 @@ export async function resolveSkills(db, input, log) {
|
|
|
128
122
|
},
|
|
129
123
|
format: "capybara",
|
|
130
124
|
manifest: p.manifest,
|
|
125
|
+
scope: replaced?.scope ?? "agent",
|
|
126
|
+
origin: replaced?.origin ?? "org",
|
|
131
127
|
});
|
|
132
128
|
}
|
|
133
129
|
return [...effective.values()].sort((a, b) => a.skill.name < b.skill.name ? -1 : a.skill.name > b.skill.name ? 1 : 0);
|
|
134
130
|
}
|
|
135
131
|
/**
|
|
136
|
-
* The
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
* when `log` is given.
|
|
132
|
+
* The {@link BudgetTier} of a resolved skill: the agent's own (`scope` `agent`, or an org skill it
|
|
133
|
+
* shared, `known.shared`: always on, never turned off, spec §3), else builtin (a platform skill of
|
|
134
|
+
* a builtin plugin, `known.plugins`, or one of `known.ids`, as `builtinSkillIds` gives them), else
|
|
135
|
+
* the org's own (no plugin), else a plugin skill.
|
|
141
136
|
*/
|
|
142
|
-
function
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
log?.warn("pinned skill is manual-only", {
|
|
150
|
-
orgId: input.orgId,
|
|
151
|
-
agentId: input.agentId,
|
|
152
|
-
conversationId: input.conversationId,
|
|
153
|
-
skillId: id,
|
|
154
|
-
name: m.skill.name,
|
|
155
|
-
version: m.skill.version,
|
|
156
|
-
});
|
|
157
|
-
continue;
|
|
158
|
-
}
|
|
159
|
-
const r = byId.get(id);
|
|
160
|
-
if (!r)
|
|
161
|
-
continue;
|
|
162
|
-
const { name, version, source } = r.skill;
|
|
163
|
-
out.push({ id, version, name, source, manifest: r.manifest });
|
|
164
|
-
if (out.length >= PINNED_SKILLS_LIMITS.count)
|
|
165
|
-
break;
|
|
137
|
+
export function budgetTier(r, known) {
|
|
138
|
+
if (r.scope === "agent" || known.shared.has(r.skill.id))
|
|
139
|
+
return 0;
|
|
140
|
+
const plugin = r.skill.plugin;
|
|
141
|
+
if ((r.origin === "platform" && plugin !== undefined && known.plugins.has(plugin)) ||
|
|
142
|
+
known.ids.has(r.skill.id)) {
|
|
143
|
+
return 1;
|
|
166
144
|
}
|
|
167
|
-
return
|
|
145
|
+
return plugin === undefined ? 2 : 3;
|
|
168
146
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const q = b[i];
|
|
172
|
-
return q !== undefined && p.id === q.id && p.version === q.version && p.source === q.source;
|
|
173
|
-
});
|
|
174
|
-
const storageUnavailable = (message) => new ApiError("storage.unavailable", message);
|
|
175
|
-
/** `details[0].reason` of a pinned SKILL.md that cannot be used whatever the retries. */
|
|
176
|
-
const PINNED_UNREADABLE = "pinned_unreadable";
|
|
177
|
-
/** Read attempts per pinned SKILL.md (a transient storage error is retried once). */
|
|
178
|
-
const PINNED_READ_ATTEMPTS = 2;
|
|
147
|
+
/** The characters a described entry takes in the listing: its line and the line break. */
|
|
148
|
+
export const catalogLineChars = (s) => [...catalogLine(s)].length + 1;
|
|
179
149
|
/**
|
|
180
|
-
* The
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
150
|
+
* The catalog budget (skills default-on spec §7): the entries ranked by `tierOf` (then by name, in
|
|
151
|
+
* code point order) keep their descriptions while the running total of their rendered lines
|
|
152
|
+
* ({@link catalogLineChars}) stays within `budget`; the first one past it and every one after it
|
|
153
|
+
* are name-only. Pure and deterministic; `tierOf` is only called when the whole listing does not
|
|
154
|
+
* fit. Entries keep their input order; any `nameOnly` they carry is replaced.
|
|
184
155
|
*/
|
|
185
|
-
export function
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
* `storage.unavailable` (Decision 9: the run fails before any model request):
|
|
197
|
-
* - a read error is retried once ({@link PINNED_READ_ATTEMPTS}), then is transient (the user
|
|
198
|
-
* sends again);
|
|
199
|
-
* - a manifest without SKILL.md, a missing object, an integrity mismatch, non-UTF-8 or an
|
|
200
|
-
* unparsable file is permanent: logged at `error` with the skill id and source, and the error
|
|
201
|
-
* carries `details: [{ reason: "pinned_unreadable", skillId, name, source }]`
|
|
202
|
-
* ({@link pinnedFailureText} turns it into an owner-facing message).
|
|
203
|
-
*/
|
|
204
|
-
export async function loadPinnedBodies(storage, orgId, pinned, opts = {}) {
|
|
205
|
-
if (pinned.length === 0)
|
|
206
|
-
return [];
|
|
207
|
-
storage.assertAvailable();
|
|
208
|
-
const out = [];
|
|
209
|
-
for (const p of pinned) {
|
|
210
|
-
// a platform version (`platform:<prefix>`) is read from deployment/ (ruling D2)
|
|
211
|
-
const { store, prefix } = skillFileStore(storage, orgId, p.source);
|
|
212
|
-
const unreadable = (problem) => {
|
|
213
|
-
opts.log?.error("pinned skill unreadable", {
|
|
214
|
-
orgId,
|
|
215
|
-
skillId: p.id,
|
|
216
|
-
version: p.version,
|
|
217
|
-
source: p.source,
|
|
218
|
-
problem,
|
|
219
|
-
});
|
|
220
|
-
return new ApiError("storage.unavailable", `Pinned skill ${p.name} ${problem}`, [
|
|
221
|
-
{ reason: PINNED_UNREADABLE, skillId: p.id, name: p.name, source: p.source },
|
|
222
|
-
]);
|
|
223
|
-
};
|
|
224
|
-
const entry = p.manifest.files.find((f) => f.path === SKILL_ENTRY_FILE);
|
|
225
|
-
if (!entry)
|
|
226
|
-
throw unreadable(`has no ${SKILL_ENTRY_FILE} in its manifest`);
|
|
227
|
-
let bytes = null;
|
|
228
|
-
for (let attempt = 1; bytes === null; attempt++) {
|
|
229
|
-
let got;
|
|
230
|
-
try {
|
|
231
|
-
got = await store.get(`${prefix}${SKILL_ENTRY_FILE}`, opts.signal && { signal: opts.signal });
|
|
232
|
-
if (got)
|
|
233
|
-
bytes = new Uint8Array(await new Response(got.body).arrayBuffer());
|
|
234
|
-
}
|
|
235
|
-
catch {
|
|
236
|
-
if (attempt >= PINNED_READ_ATTEMPTS) {
|
|
237
|
-
throw storageUnavailable(`Cannot read pinned skill ${p.name} from storage`);
|
|
238
|
-
}
|
|
239
|
-
continue;
|
|
240
|
-
}
|
|
241
|
-
if (!got)
|
|
242
|
-
throw unreadable("is missing from storage");
|
|
243
|
-
}
|
|
244
|
-
if (bytes.byteLength !== entry.size ||
|
|
245
|
-
createHash("sha256").update(bytes).digest("hex") !== entry.sha256) {
|
|
246
|
-
throw unreadable("failed its integrity check");
|
|
247
|
-
}
|
|
248
|
-
let text;
|
|
249
|
-
try {
|
|
250
|
-
text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
251
|
-
}
|
|
252
|
-
catch {
|
|
253
|
-
throw unreadable("is not UTF-8");
|
|
254
|
-
}
|
|
255
|
-
const parsed = parseSkillMd(text, { invocationKeys: false });
|
|
256
|
-
if ("errors" in parsed)
|
|
257
|
-
throw unreadable("cannot be parsed");
|
|
258
|
-
out.push({ id: p.id, version: p.version, name: p.name, source: p.source, body: parsed.body });
|
|
259
|
-
}
|
|
260
|
-
return out;
|
|
261
|
-
}
|
|
262
|
-
/**
|
|
263
|
-
* The pinned skills that fit: in order while the running total of UTF-8 body bytes stays within
|
|
264
|
-
* {@link PINNED_SKILLS_LIMITS}.totalBytes; the first that does not fit and every later one are
|
|
265
|
-
* dropped with a warning (Review Focus 4: a pinned skill's new version can push a saved set over).
|
|
266
|
-
*/
|
|
267
|
-
export function fitPinned(pinned, log, input) {
|
|
268
|
-
const enc = new TextEncoder();
|
|
156
|
+
export async function applyCatalogBudget(skills, budget, tierOf) {
|
|
157
|
+
const described = skills.map(({ nameOnly: _n, ...s }) => s);
|
|
158
|
+
const cost = described.map(catalogLineChars);
|
|
159
|
+
const characters = cost.reduce((a, b) => a + b, 0);
|
|
160
|
+
if (characters <= budget)
|
|
161
|
+
return { skills: described, characters, nameOnly: 0 };
|
|
162
|
+
const tier = await tierOf();
|
|
163
|
+
const order = described
|
|
164
|
+
.map((s, i) => ({ s, i, t: tier(s) }))
|
|
165
|
+
.sort((a, b) => a.t !== b.t ? a.t - b.t : a.s.name < b.s.name ? -1 : a.s.name > b.s.name ? 1 : a.i - b.i);
|
|
166
|
+
const cut = new Set();
|
|
269
167
|
let total = 0;
|
|
270
|
-
for (
|
|
271
|
-
|
|
272
|
-
if (total
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
conversationId: input.conversationId,
|
|
277
|
-
kept: pinned.slice(0, i).map((p) => p.name),
|
|
278
|
-
dropped: pinned.slice(i).map((p) => p.name),
|
|
279
|
-
maxBytes: PINNED_SKILLS_LIMITS.totalBytes,
|
|
280
|
-
});
|
|
281
|
-
return pinned.slice(0, i);
|
|
282
|
-
}
|
|
168
|
+
for (const { i } of order) {
|
|
169
|
+
const c = cost[i];
|
|
170
|
+
if (cut.size === 0 && total + c <= budget)
|
|
171
|
+
total += c;
|
|
172
|
+
else
|
|
173
|
+
cut.add(i);
|
|
283
174
|
}
|
|
284
|
-
return
|
|
175
|
+
return {
|
|
176
|
+
skills: described.map((s, i) => (cut.has(i) ? { ...s, nameOnly: true } : s)),
|
|
177
|
+
characters,
|
|
178
|
+
nameOnly: cut.size,
|
|
179
|
+
};
|
|
285
180
|
}
|
|
286
181
|
/** `skills_catalog` 的幂等键:每次运行最多写一份。 */
|
|
287
182
|
/**
|
|
@@ -337,66 +232,74 @@ export async function lockLatestCatalog(db, conversationId) {
|
|
|
337
232
|
.executeTakeFirst();
|
|
338
233
|
return last ? last.payload : undefined;
|
|
339
234
|
}
|
|
340
|
-
/** How often run start re-resolves when the pinned set changed while its bodies were read. */
|
|
341
|
-
const RECORD_ATTEMPTS = 3;
|
|
342
235
|
/**
|
|
343
236
|
* 运行开始时记录技能目录快照:解析生效的技能,与日志里最新一份不同才写(带幂等键,崩溃重试不重复)。
|
|
344
237
|
* 从没有快照、现在也没有技能 → 不写(没有技能的 agent 不出现目录);之前有、现在全没了 → 写空快照(模型据此得知被移除)。
|
|
345
238
|
* 解析、比较、追加在一个事务里、先锁会话行:否则在解析与追加之间提交的拒绝 + 回退快照会被过时的草稿条目盖回去。
|
|
346
239
|
* 解析只读 skills / agents / 申请(不加锁),不会与别的路径形成死锁。
|
|
347
240
|
*
|
|
348
|
-
*
|
|
349
|
-
*
|
|
350
|
-
*
|
|
351
|
-
*
|
|
352
|
-
*
|
|
353
|
-
*
|
|
241
|
+
* The snapshot also carries each skill's `plugin` and the Claude Code tool-name map (`toolMap`,
|
|
242
|
+
* iff an effective skill has source format `claude-code`). It never carries `pinned` any more
|
|
243
|
+
* (skills default-on spec §8): a conversation whose latest snapshot has pins gets one without them,
|
|
244
|
+
* and the request tells the model they were removed. Run start reads no object storage.
|
|
245
|
+
*
|
|
246
|
+
* The catalog budget (`skills.catalogBudgetChars`, spec §7) is applied here and recorded in the
|
|
247
|
+
* snapshot: entries past it carry `nameOnly: true` ({@link applyCatalogBudget}); the cut is logged
|
|
248
|
+
* as `skills.catalog_over_budget`. A changed budget writes a new snapshot at the next run start
|
|
249
|
+
* only when an entry crosses it. Snapshots appended elsewhere (a skill registration, a trial's
|
|
250
|
+
* revert) carry the entries forward as they are; the next run start applies the budget again.
|
|
354
251
|
*/
|
|
355
252
|
let SkillsCatalogService = class SkillsCatalogService {
|
|
356
253
|
db;
|
|
357
|
-
storage;
|
|
358
254
|
eventLog;
|
|
359
255
|
log;
|
|
360
256
|
txHost;
|
|
361
|
-
|
|
257
|
+
config;
|
|
258
|
+
constructor(db, eventLog, log, txHost, config) {
|
|
362
259
|
this.db = db;
|
|
363
|
-
this.storage = storage;
|
|
364
260
|
this.eventLog = eventLog;
|
|
365
261
|
this.log = log;
|
|
366
262
|
this.txHost = txHost;
|
|
263
|
+
this.config = config;
|
|
367
264
|
}
|
|
368
265
|
/**
|
|
369
266
|
* Records the run start's snapshot (see the class comment). `opts.log`: the run's logger
|
|
370
267
|
* (default the kernel logger).
|
|
371
268
|
*/
|
|
372
269
|
async record(input, opts = {}) {
|
|
373
|
-
const
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
// Warn about manual-only pins once, on the first attempt
|
|
377
|
-
const first = pinnedCandidates(forModel(all, input), input.agent, input, all, attempt === 1 ? log : undefined);
|
|
378
|
-
const pinned = fitPinned(await loadPinnedBodies(this.storage, input.orgId, first, { log }), log, input);
|
|
379
|
-
const toSeq = await this.append(input, first, pinned, log);
|
|
380
|
-
if (toSeq === "retry")
|
|
381
|
-
continue;
|
|
382
|
-
if (toSeq !== null)
|
|
383
|
-
await this.eventLog.notify(input.conversationId, toSeq);
|
|
384
|
-
return;
|
|
385
|
-
}
|
|
386
|
-
throw new ApiError("conflict", "The pinned skills kept changing while the run started; send the message again.");
|
|
270
|
+
const toSeq = await this.append(input, opts.log ?? this.log);
|
|
271
|
+
if (toSeq !== null)
|
|
272
|
+
await this.eventLog.notify(input.conversationId, toSeq);
|
|
387
273
|
}
|
|
388
|
-
/**
|
|
389
|
-
async append(input,
|
|
274
|
+
/** Under the conversation row lock, resolves the skills and appends a changed snapshot. */
|
|
275
|
+
async append(input, log) {
|
|
390
276
|
const last = await lockLatestCatalog(this.db.db, input.conversationId);
|
|
391
|
-
const all = await resolveSkills(this.db.db, input);
|
|
277
|
+
const all = await resolveSkills(this.db.db, input, log);
|
|
392
278
|
const resolved = forModel(all, input, log);
|
|
393
|
-
|
|
394
|
-
|
|
279
|
+
const budget = this.config.get().skills.catalogBudgetChars;
|
|
280
|
+
const cut = await applyCatalogBudget(resolved.map((r) => r.skill), budget, async () => {
|
|
281
|
+
const plugins = await builtinSkillPlugins(this.db.db);
|
|
282
|
+
const ids = new Set(await builtinSkillIds(this.db.db, input.orgId));
|
|
283
|
+
const shared = new Set((await agentOwnSkillIds(this.db.db, input)).shared);
|
|
284
|
+
// names are unique in the catalog
|
|
285
|
+
const tiers = new Map(resolved.map((r) => [r.skill.name, budgetTier(r, { plugins, ids, shared })]));
|
|
286
|
+
return (s) => tiers.get(s.name) ?? 3;
|
|
287
|
+
});
|
|
288
|
+
const skills = cut.skills;
|
|
289
|
+
if (cut.nameOnly > 0) {
|
|
290
|
+
this.log.info("skills.catalog_over_budget", {
|
|
291
|
+
orgId: input.orgId,
|
|
292
|
+
agentId: input.agentId,
|
|
293
|
+
conversationId: input.conversationId,
|
|
294
|
+
runId: input.runId,
|
|
295
|
+
entries: skills.length,
|
|
296
|
+
nameOnly: cut.nameOnly,
|
|
297
|
+
characters: cut.characters,
|
|
298
|
+
budget,
|
|
299
|
+
});
|
|
395
300
|
}
|
|
396
|
-
const skills = resolved.map((r) => r.skill);
|
|
397
301
|
const next = {
|
|
398
302
|
skills,
|
|
399
|
-
...(pinned.length > 0 && { pinned }),
|
|
400
303
|
// The model's (truncated) skills as before phase D, plus manual-only ones: a person can
|
|
401
304
|
// invoke one whose body names Claude tools (batch 1 review M8)
|
|
402
305
|
...([...resolved, ...all.filter((r) => !invocationOf(r.manifest).model)].some((r) => r.format === "claude-code") && {
|
|
@@ -422,9 +325,9 @@ __decorate([
|
|
|
422
325
|
SkillsCatalogService = __decorate([
|
|
423
326
|
Injectable(),
|
|
424
327
|
__param(0, Inject(KernelDb)),
|
|
425
|
-
__param(1, Inject(
|
|
426
|
-
__param(2, Inject(
|
|
427
|
-
__param(3, Inject(
|
|
428
|
-
__param(4, Inject(
|
|
328
|
+
__param(1, Inject(EventLog)),
|
|
329
|
+
__param(2, Inject(KERNEL_LOGGER)),
|
|
330
|
+
__param(3, Inject(TransactionHost)),
|
|
331
|
+
__param(4, Inject(KernelConfigService))
|
|
429
332
|
], SkillsCatalogService);
|
|
430
333
|
export { SkillsCatalogService };
|
|
@@ -21,9 +21,9 @@ export interface CancelledDrafts {
|
|
|
21
21
|
* `EventLog.append` takes) and reads the latest snapshot under it, so no other snapshot slips in
|
|
22
22
|
* between "read latest" and "append". Returns the seq written, or null when nothing was written;
|
|
23
23
|
* the caller calls `eventLog.notify` after the commit.
|
|
24
|
-
* `derive` gets the whole latest payload, so `
|
|
25
|
-
*
|
|
26
|
-
*
|
|
24
|
+
* `derive` gets the whole latest payload, so `toolMap` is carried forward (it is only recomputed at
|
|
25
|
+
* run start). `pinned` of an old snapshot never is: new snapshots carry no pinned skills (skills
|
|
26
|
+
* default-on spec §8).
|
|
27
27
|
*/
|
|
28
28
|
export declare function appendConversationCatalog(deps: ConversationCatalogDeps, conversationId: string, derive: (base: SkillsSnapshot) => SkillsSnapshot | null, idemKey: string, runId?: string | null): Promise<number | null>;
|
|
29
29
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { sql } from "kysely";
|
|
2
2
|
import { audit } from "../identity/audit.js";
|
|
3
|
-
import { sameSnapshot
|
|
4
|
-
import {
|
|
3
|
+
import { sameSnapshot } from "../runtime/context/skills.js";
|
|
4
|
+
import { invocationOf, lockLatestCatalog } from "./catalog.js";
|
|
5
5
|
const byName = (a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
|
|
6
6
|
/**
|
|
7
7
|
* In the caller's transaction, derives the conversation's next skills catalog snapshot from its
|
|
@@ -9,9 +9,9 @@ const byName = (a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
|
|
|
9
9
|
* `EventLog.append` takes) and reads the latest snapshot under it, so no other snapshot slips in
|
|
10
10
|
* between "read latest" and "append". Returns the seq written, or null when nothing was written;
|
|
11
11
|
* the caller calls `eventLog.notify` after the commit.
|
|
12
|
-
* `derive` gets the whole latest payload, so `
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* `derive` gets the whole latest payload, so `toolMap` is carried forward (it is only recomputed at
|
|
13
|
+
* run start). `pinned` of an old snapshot never is: new snapshots carry no pinned skills (skills
|
|
14
|
+
* default-on spec §8).
|
|
15
15
|
*/
|
|
16
16
|
export async function appendConversationCatalog(deps, conversationId, derive, idemKey, runId) {
|
|
17
17
|
const base = (await lockLatestCatalog(deps.db.db, conversationId)) ?? { skills: [] };
|
|
@@ -19,11 +19,8 @@ export async function appendConversationCatalog(deps, conversationId, derive, id
|
|
|
19
19
|
if (derived === null)
|
|
20
20
|
return null;
|
|
21
21
|
const skills = [...derived.skills].sort(byName);
|
|
22
|
-
const live = (p) => skills.some((s) => s.id === p.id && s.version === p.version && s.source === p.source);
|
|
23
|
-
const pinned = fitPinned((derived.pinned ?? []).filter(live), deps.log, { conversationId });
|
|
24
22
|
const next = {
|
|
25
23
|
skills,
|
|
26
|
-
...(pinned.length > 0 && { pinned }),
|
|
27
24
|
...(derived.toolMap !== undefined && { toolMap: derived.toolMap }),
|
|
28
25
|
};
|
|
29
26
|
if (sameSnapshot(base, next))
|
|
@@ -88,7 +85,6 @@ export async function revertTrialCatalog(deps, req) {
|
|
|
88
85
|
if (!base.skills.some((s) => s.source === req.object_prefix))
|
|
89
86
|
return null;
|
|
90
87
|
const rest = base.skills.filter((s) => s.source !== req.object_prefix);
|
|
91
|
-
// The draft's pinned entry goes (Decision 8): the next run start pins the real version
|
|
92
88
|
return {
|
|
93
89
|
...base,
|
|
94
90
|
// A manual-only current version (phase D) stays out of the model's catalog
|
|
@@ -104,9 +100,6 @@ export async function revertTrialCatalog(deps, req) {
|
|
|
104
100
|
},
|
|
105
101
|
]
|
|
106
102
|
: rest,
|
|
107
|
-
...(base.pinned && {
|
|
108
|
-
pinned: base.pinned.filter((p) => p.source !== req.object_prefix),
|
|
109
|
-
}),
|
|
110
103
|
};
|
|
111
104
|
}, `skills_catalog:revert:${req.id}`);
|
|
112
105
|
}
|
package/dist/skills/invoke.d.ts
CHANGED
|
@@ -61,7 +61,7 @@ export declare const notInvocable: (reason: NotInvocableReason, name: string) =>
|
|
|
61
61
|
export declare function recordedSkillBlocked(db: KernelSchemaDb, a: {
|
|
62
62
|
orgId: string;
|
|
63
63
|
agentId: string;
|
|
64
|
-
agent: Pick<AgentDefinition, "
|
|
64
|
+
agent: Pick<AgentDefinition, "disabledSkills">;
|
|
65
65
|
conversationId: string;
|
|
66
66
|
skillId: string;
|
|
67
67
|
}): Promise<NotInvocableReason | null>;
|
|
@@ -93,7 +93,7 @@ export declare class SkillInvoker {
|
|
|
93
93
|
list(a: {
|
|
94
94
|
orgId: string;
|
|
95
95
|
agentId: string;
|
|
96
|
-
agent: Pick<AgentDefinition, "
|
|
96
|
+
agent: Pick<AgentDefinition, "disabledSkills">;
|
|
97
97
|
conversationId?: string;
|
|
98
98
|
}): Promise<InvocableSkill[]>;
|
|
99
99
|
/**
|
|
@@ -41,7 +41,9 @@ export declare class SkillsController {
|
|
|
41
41
|
list(principal: Principal, org: OrgContext): Promise<{
|
|
42
42
|
skills: SkillSummary[];
|
|
43
43
|
}>;
|
|
44
|
-
get(principal: Principal, org: OrgContext, id: string): Promise<SkillDetail
|
|
44
|
+
get(principal: Principal, org: OrgContext, id: string): Promise<SkillDetail & {
|
|
45
|
+
agentsOff: number;
|
|
46
|
+
}>;
|
|
45
47
|
/**
|
|
46
48
|
* Sets 可共享 on the org's own skill (`{ shareable }` -> 200 `{ id, shareable }`): only an org
|
|
47
49
|
* skill of the org's own (P3-6: an agent's skill or a copy of another owner's platform skill ->
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type DisabledSkillRef } from "../agents/definition.js";
|
|
2
2
|
import { type Owner } from "../catalog/ownership.js";
|
|
3
3
|
import { type OwnerVersion, PlatformComponents } from "../catalog/platform-components.js";
|
|
4
4
|
import { AttachmentsService, type CreatedAttachment } from "../conversations/attachments.service.js";
|
|
@@ -53,12 +53,6 @@ export interface SkillSummary {
|
|
|
53
53
|
plugin: string | null;
|
|
54
54
|
/** The format of the plugin the current version came from. */
|
|
55
55
|
sourceFormat: SourceFormat;
|
|
56
|
-
/** The plugin suggests pinning the current version (spec §9.1). */
|
|
57
|
-
suggestPinned: boolean;
|
|
58
|
-
/** SKILL.md size of the current version, in bytes (0 when the manifest has none). */
|
|
59
|
-
entryBytes: number;
|
|
60
|
-
/** Token estimate of the SKILL.md of the current version (ASCII rule: bytes / 4). */
|
|
61
|
-
tokenEstimate: number;
|
|
62
56
|
/** Phase D: the current version is manual-only (not in the model's catalog). */
|
|
63
57
|
manual: boolean;
|
|
64
58
|
/** Phase D: the current version runs as a sub-agent when a person invokes it. */
|
|
@@ -84,6 +78,12 @@ export interface SkillSummary {
|
|
|
84
78
|
* selects this skill.
|
|
85
79
|
*/
|
|
86
80
|
linkedIds?: string[];
|
|
81
|
+
/**
|
|
82
|
+
* In the library list only (true or false on every item there, absent elsewhere): a platform
|
|
83
|
+
* skill of a builtin plugin (`platformBuiltin`: builtin and platform-owned) or the org's pinned
|
|
84
|
+
* copy of one. Every agent has it and none can turn it off (skills default-on spec §3).
|
|
85
|
+
*/
|
|
86
|
+
builtin?: boolean;
|
|
87
87
|
}
|
|
88
88
|
/** 技能的一个版本(含文件清单)。 */
|
|
89
89
|
export interface SkillVersionView {
|
|
@@ -111,33 +111,23 @@ export interface UploadedSkill {
|
|
|
111
111
|
created: boolean;
|
|
112
112
|
}
|
|
113
113
|
/**
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
| "manual_only";
|
|
124
|
-
/**
|
|
125
|
-
* Checks `skills.pinned` of an agent definition in the caller's transaction (the org row is locked,
|
|
126
|
-
* like {@link assertOrgSkills}); throws 400 `agent.pinned_invalid` with one detail per problem
|
|
127
|
-
* (`{ skill, reason, totalBytes? }`):
|
|
128
|
-
* - `duplicate`: an id listed twice; `too_many`: every id past {@link PINNED_SKILLS_LIMITS}.count;
|
|
129
|
-
* - each newly added id (not in `kept`, the current definition's pinned ids) must be a live org
|
|
130
|
-
* skill listed in `skills.orgSkills` (else `not_selected`) or a live skill of this agent
|
|
131
|
-
* (`agentId`; null when creating), else `not_found`. Kept ids are not re-checked: a pinned skill
|
|
132
|
-
* deleted later does not block other edits (the run ignores it);
|
|
133
|
-
* - `manual_only` (phase D): a newly added id whose current version is manual-only
|
|
134
|
-
* (`invocation.model === false`); a kept one that became manual-only is dropped at run time;
|
|
135
|
-
* - `too_large`: the current SKILL.md sizes of the live pinned skills total more than
|
|
136
|
-
* {@link PINNED_SKILLS_LIMITS}.totalBytes (named by the first skill past the limit). Checked only
|
|
137
|
-
* when the pinned list changed: a pinned skill's new version never blocks an unrelated edit (the
|
|
138
|
-
* run keeps what fits).
|
|
114
|
+
* Checks `disabledSkills` of an agent definition in the caller's transaction (skills default-on
|
|
115
|
+
* spec §4); throws 400 `validation_failed` with one detail per problem at `disabledSkills.<i>`:
|
|
116
|
+
* - a plugin entry must name a plugin with at least one skill usable in the org, and each name must
|
|
117
|
+
* be a skill of it;
|
|
118
|
+
* - a skill entry must name a usable org skill without a plugin;
|
|
119
|
+
* - a builtin plugin, a builtin skill, the agent's own skill or an org skill it shared cannot be
|
|
120
|
+
* turned off.
|
|
121
|
+
* What the current version already turns off (`kept`) is not checked again: a whole entry, or the
|
|
122
|
+
* names a plugin entry kept, so a plugin switched off or uninstalled later never blocks other edits.
|
|
139
123
|
*/
|
|
140
|
-
export declare function
|
|
124
|
+
export declare function assertDisabledSkills(db: KernelSchemaDb, a: {
|
|
125
|
+
orgId: string;
|
|
126
|
+
/** Null when creating. */
|
|
127
|
+
agentId: string | null;
|
|
128
|
+
disabled: readonly DisabledSkillRef[];
|
|
129
|
+
kept?: readonly DisabledSkillRef[];
|
|
130
|
+
}): Promise<void>;
|
|
141
131
|
/**
|
|
142
132
|
* 技能库(M5 T13):组织技能的上传(新技能或新版本)、列表、详情与软删除。
|
|
143
133
|
* 字节在对象存储 `kernel/<orgId>/skills/<uploadId>/<path>`,元数据在 PG;无进程内状态,可多副本共用。
|
|
@@ -217,8 +207,6 @@ export declare class SkillsService {
|
|
|
217
207
|
approvedBy?: string;
|
|
218
208
|
/** The catalog version's source format (default capybara). */
|
|
219
209
|
format?: SourceFormat;
|
|
220
|
-
/** The plugin manifest suggests pinning this skill (spec §9.1). */
|
|
221
|
-
suggestPinned?: boolean;
|
|
222
210
|
};
|
|
223
211
|
/**
|
|
224
212
|
* The files are already stored (no storage I/O here, so it may join a transaction): at
|
|
@@ -258,7 +246,9 @@ export declare class SkillsService {
|
|
|
258
246
|
/**
|
|
259
247
|
* The org skill library, sorted by name: the org's live `scope=org` skills except copies linked
|
|
260
248
|
* to a platform skill without a pin, and the platform skills on in the org (phase 2,
|
|
261
|
-
* `usableSkills`; `origin` tells them apart), each with the ids of those copies (`linkedIds`)
|
|
249
|
+
* `usableSkills`; `origin` tells them apart), each with the ids of those copies (`linkedIds`);
|
|
250
|
+
* every item carries `builtin`: true for a platform skill of a builtin plugin or the org's pinned
|
|
251
|
+
* copy of one (every agent has it, none can turn it off).
|
|
262
252
|
*/
|
|
263
253
|
list(orgId: string): Promise<SkillSummary[]>;
|
|
264
254
|
/**
|
|
@@ -279,7 +269,18 @@ export declare class SkillsService {
|
|
|
279
269
|
* content under its own id, so its detail is the platform skill's (its id, versions and body;
|
|
280
270
|
* 404 while that skill is off in the org); a pinned copy keeps its own (Task 10).
|
|
281
271
|
*/
|
|
282
|
-
get(orgId: string, skillId: string): Promise<SkillDetail
|
|
272
|
+
get(orgId: string, skillId: string): Promise<SkillDetail & {
|
|
273
|
+
agentsOff: number;
|
|
274
|
+
}>;
|
|
275
|
+
/**
|
|
276
|
+
* How many of the org's live agents turn the skill off in their current version (skills
|
|
277
|
+
* default-on spec §10: 「N 个智能体关闭了它」): matched by the rule of `agentSkills` against the
|
|
278
|
+
* skill as the org's usable set holds it. A builtin skill, one not usable in the org and an org
|
|
279
|
+
* skill for the agent that shared it count 0.
|
|
280
|
+
*/
|
|
281
|
+
private agentsOff;
|
|
282
|
+
/** The skill's detail without `agentsOff` (no agents scan; for names and checks). */
|
|
283
|
+
detail(orgId: string, skillId: string): Promise<SkillDetail>;
|
|
283
284
|
/**
|
|
284
285
|
* A platform skill's detail (phase 2): only while it is on in the org, else `skill.not_found`.
|
|
285
286
|
* Its versions are the platform skill's.
|