@capybara-hq/kernel 0.1.0-rc.19 → 0.1.0-rc.20
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/bootstrap.json +25 -25
- package/dist/admin/admin-agents.controller.d.ts +28 -0
- package/dist/admin/admin-agents.controller.js +79 -0
- package/dist/admin/admin-connectors.controller.d.ts +29 -0
- package/dist/admin/admin-connectors.controller.js +79 -0
- package/dist/admin/admin-items.schemas.d.ts +42 -0
- package/dist/admin/admin-items.schemas.js +48 -0
- package/dist/admin/admin.controller.d.ts +11 -20
- package/dist/admin/admin.controller.js +28 -34
- package/dist/admin/admin.module.d.ts +4 -1
- package/dist/admin/admin.module.js +50 -4
- package/dist/admin/admin.schemas.d.ts +4 -0
- package/dist/admin/admin.schemas.js +4 -1
- package/dist/admin/audit.controller.d.ts +14 -0
- package/dist/admin/audit.controller.js +42 -0
- package/dist/admin/audit.schemas.d.ts +8 -0
- package/dist/admin/audit.schemas.js +17 -0
- package/dist/admin/health.service.d.ts +104 -0
- package/dist/admin/health.service.js +246 -0
- package/dist/admin/overview.controller.d.ts +31 -0
- package/dist/admin/overview.controller.js +78 -0
- package/dist/admin/overview.schemas.d.ts +8 -0
- package/dist/admin/overview.schemas.js +13 -0
- package/dist/admin/overview.service.d.ts +112 -0
- package/dist/admin/overview.service.js +223 -0
- package/dist/admin/platform-audit.service.d.ts +41 -0
- package/dist/admin/platform-audit.service.js +70 -0
- package/dist/admin/usage.service.d.ts +149 -0
- package/dist/admin/usage.service.js +321 -0
- package/dist/agents/admin-agents.d.ts +92 -0
- package/dist/agents/admin-agents.js +170 -0
- package/dist/agents/agents.module.d.ts +4 -3
- package/dist/agents/agents.module.js +7 -3
- package/dist/agents/agents.service.d.ts +41 -3
- package/dist/agents/agents.service.js +113 -27
- package/dist/agents/definition.d.ts +16 -0
- package/dist/agents/definition.js +32 -2
- package/dist/agents/org-templates.js +4 -0
- package/dist/background/launch.d.ts +1 -1
- package/dist/background/launch.js +3 -3
- package/dist/background/tasks.service.d.ts +35 -3
- package/dist/background/tasks.service.js +91 -36
- package/dist/catalog/catalog.module.js +8 -2
- package/dist/channels/channels.module.js +11 -2
- package/dist/channels/supervisor.d.ts +2 -0
- package/dist/channels/supervisor.js +4 -0
- package/dist/conversations/events.js +1 -1
- package/dist/conversations/titles.js +4 -8
- package/dist/db/kernel-schema.d.ts +8 -1
- package/dist/devices/devices.module.js +5 -2
- package/dist/errors.d.ts +22 -2
- package/dist/errors.js +22 -2
- package/dist/evals/evals.module.js +11 -2
- package/dist/extensions/permission-view.js +3 -3
- package/dist/http/api.module.js +10 -1
- package/dist/identity/settings.js +3 -2
- package/dist/identity/write-actor.d.ts +11 -0
- package/dist/identity/write-actor.js +7 -0
- package/dist/inbox/inbox.service.d.ts +2 -1
- package/dist/inbox/platform-inbox.service.d.ts +7 -1
- package/dist/inbox/platform-inbox.service.js +20 -2
- package/dist/infra/presence/presence.module.d.ts +6 -0
- package/dist/infra/presence/presence.module.js +22 -0
- package/dist/infra/presence/replica-presence.d.ts +87 -0
- package/dist/infra/presence/replica-presence.js +189 -0
- package/dist/kernel.module.js +3 -0
- package/dist/lifecycle/kernel-lifecycle.d.ts +3 -1
- package/dist/lifecycle/kernel-lifecycle.js +17 -3
- package/dist/local-devices/local-device-gateway.d.ts +6 -0
- package/dist/local-devices/local-device-gateway.js +12 -0
- package/dist/overrides.d.ts +7 -1
- package/dist/overrides.js +4 -0
- package/dist/platform/exclusions.js +15 -0
- package/dist/platform/operation.d.ts +1 -1
- package/dist/platform/operation.js +1 -1
- package/dist/platform/ops/admin-items.ops.d.ts +37 -0
- package/dist/platform/ops/admin-items.ops.js +278 -0
- package/dist/platform/ops/admin.ops.d.ts +10 -10
- package/dist/platform/ops/admin.ops.js +111 -42
- package/dist/platform/ops/agent-skills.ops.d.ts +29 -3
- package/dist/platform/ops/agent-skills.ops.js +290 -7
- package/dist/platform/ops/inbox.ops.js +7 -4
- package/dist/platform/ops/platform.ops.js +1 -1
- package/dist/platform/ops/skills.ops.js +1 -57
- 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 +8 -0
- package/dist/roles/gateway-role.d.ts +4 -0
- package/dist/roles/gateway-role.js +8 -0
- package/dist/runtime/run-jobs.js +4 -2
- package/dist/sandbox/sandbox-file-reader.d.ts +35 -0
- package/dist/sandbox/sandbox-file-reader.js +98 -0
- package/dist/skills/agent-skills.controller.d.ts +48 -0
- package/dist/skills/agent-skills.controller.js +131 -0
- package/dist/skills/agent-skills.service.d.ts +262 -0
- package/dist/skills/agent-skills.service.js +996 -0
- package/dist/skills/catalog.d.ts +8 -6
- package/dist/skills/catalog.js +8 -4
- package/dist/skills/changes.controller.d.ts +5 -22
- package/dist/skills/changes.controller.js +7 -55
- package/dist/skills/changes.service.d.ts +69 -115
- package/dist/skills/changes.service.js +249 -599
- package/dist/skills/conversation-catalog.d.ts +53 -0
- package/dist/skills/conversation-catalog.js +149 -0
- package/dist/skills/invocation-keys.d.ts +1 -1
- package/dist/skills/invocation-keys.js +1 -1
- package/dist/skills/package.d.ts +0 -5
- package/dist/skills/package.js +0 -14
- package/dist/skills/skills.controller.js +1 -10
- package/dist/skills/skills.module.js +15 -2
- package/dist/skills/skills.schemas.d.ts +11 -15
- package/dist/skills/skills.schemas.js +27 -20
- package/dist/skills/skills.service.d.ts +37 -30
- package/dist/skills/skills.service.js +107 -59
- package/dist/skills/usable.d.ts +4 -3
- package/dist/skills/usable.js +13 -4
- package/dist/tools/admin-connectors.d.ts +69 -0
- package/dist/tools/admin-connectors.js +135 -0
- package/dist/tools/builtin-names.d.ts +9 -14
- package/dist/tools/builtin-names.js +13 -22
- package/dist/tools/builtins/builtin-tools.d.ts +2 -3
- package/dist/tools/builtins/builtin-tools.js +21 -26
- package/dist/tools/builtins/sandbox/bash.js +2 -2
- package/dist/tools/builtins/skill-load.js +1 -0
- package/dist/tools/connectors.controller.d.ts +5 -1
- package/dist/tools/connectors.controller.js +17 -3
- package/dist/tools/connectors.service.d.ts +20 -1
- package/dist/tools/connectors.service.js +61 -0
- package/dist/tools/legacy-keys.js +0 -1
- package/dist/tools/org-tool-switches.d.ts +3 -2
- package/dist/tools/org-tool-switches.js +4 -4
- package/dist/tools/policy.d.ts +7 -9
- package/dist/tools/policy.js +11 -22
- package/dist/tools/tools.module.js +3 -0
- package/package.json +1 -1
- package/src/migrations/0109_audit_platform_idx.sql +5 -0
- package/src/migrations/0110_usage_time_idx.sql +8 -0
- package/src/migrations/0111_agent_skill_sharing.sql +22 -0
- package/src/migrations/0112_skill_share_requests.sql +4 -0
- package/dist/tools/builtins/skill-write.d.ts +0 -59
- package/dist/tools/builtins/skill-write.js +0 -244
package/dist/skills/catalog.d.ts
CHANGED
|
@@ -29,8 +29,8 @@ export interface EffectiveSkillsInput {
|
|
|
29
29
|
/** 本次运行固定的 agent 版本的定义(`skills.orgSkills` 是选中的组织技能 id)。 */
|
|
30
30
|
agent: Pick<AgentDefinition, "skills">;
|
|
31
31
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
32
|
+
* The conversation id: a pending skill change of the agent (`skill_change_requests`, a version
|
|
33
|
+
* draft) applies only in the conversation that proposed it (a trial) and is overlaid here.
|
|
34
34
|
*/
|
|
35
35
|
conversationId: string;
|
|
36
36
|
}
|
|
@@ -42,9 +42,11 @@ export interface EffectiveSkillsInput {
|
|
|
42
42
|
* - 版本取 `current_version`,描述取该版本清单里的描述。
|
|
43
43
|
* 组织技能与 agent 自己的技能同名时只保留 agent 自己的(更具体;`/skills/<name>/` 与按名字加载都不能有两个)。
|
|
44
44
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
45
|
+
* Trials: a pending version proposal of this agent made in this conversation replaces, by name,
|
|
46
|
+
* the version of its skill (the id of the existing skill, the version it would become on
|
|
47
|
+
* approval); other conversations keep `current_version`. Once approved it is the current version
|
|
48
|
+
* and every conversation gets a notice from the snapshot difference at its next run start; after
|
|
49
|
+
* a reject or cancel the proposing conversation goes back to the current version.
|
|
48
50
|
*/
|
|
49
51
|
export declare function resolveEffectiveSkills(db: KernelSchemaDb, input: EffectiveSkillsInput, log?: Pick<Logger, "warn">): Promise<CatalogSkill[]>;
|
|
50
52
|
/** The invocation metadata of a skill version: the manifest's, or the defaults when absent. */
|
|
@@ -125,7 +127,7 @@ export declare const skillsCatalogIdemKey: (runId: string) => string;
|
|
|
125
127
|
/**
|
|
126
128
|
* 在调用方事务里锁会话行(与 `EventLog.append` 同一把锁)并读最新一份技能目录快照(没有为 undefined)。
|
|
127
129
|
* `db` is the caller's transaction handle (`KernelDb.db` inside `@Transactional`).
|
|
128
|
-
* 「读最新 → 推出下一份 →
|
|
130
|
+
* 「读最新 → 推出下一份 → 追加」都在这把锁内,别的写快照的事务(运行开始、技能注册、拒绝时的回退)插不进来。
|
|
129
131
|
*/
|
|
130
132
|
export declare function lockLatestCatalog(db: KernelSchemaDb, conversationId: string): Promise<SkillsSnapshot | undefined>;
|
|
131
133
|
/**
|
package/dist/skills/catalog.js
CHANGED
|
@@ -40,9 +40,11 @@ export const PINNED_SKILLS_LIMITS = { count: 3, totalBytes: 32768 };
|
|
|
40
40
|
* - 版本取 `current_version`,描述取该版本清单里的描述。
|
|
41
41
|
* 组织技能与 agent 自己的技能同名时只保留 agent 自己的(更具体;`/skills/<name>/` 与按名字加载都不能有两个)。
|
|
42
42
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
43
|
+
* Trials: a pending version proposal of this agent made in this conversation replaces, by name,
|
|
44
|
+
* the version of its skill (the id of the existing skill, the version it would become on
|
|
45
|
+
* approval); other conversations keep `current_version`. Once approved it is the current version
|
|
46
|
+
* and every conversation gets a notice from the snapshot difference at its next run start; after
|
|
47
|
+
* a reject or cancel the proposing conversation goes back to the current version.
|
|
46
48
|
*/
|
|
47
49
|
export async function resolveEffectiveSkills(db, input, log) {
|
|
48
50
|
return forModel(await resolveSkills(db, input), input, log).map((r) => r.skill);
|
|
@@ -112,6 +114,8 @@ export async function resolveSkills(db, input, log) {
|
|
|
112
114
|
.where("agent_id", "=", input.agentId)
|
|
113
115
|
.where("org_id", "=", input.orgId)
|
|
114
116
|
.where("status", "=", "pending")
|
|
117
|
+
// a share request carries no new files: never a trial
|
|
118
|
+
.where("kind", "=", "version")
|
|
115
119
|
.execute();
|
|
116
120
|
for (const { proposed_version: p, object_prefix } of trials) {
|
|
117
121
|
effective.set(p.manifest.name, {
|
|
@@ -314,7 +318,7 @@ export const skillsCatalogIdemKey = (runId) => `skills_catalog:${runId}`;
|
|
|
314
318
|
/**
|
|
315
319
|
* 在调用方事务里锁会话行(与 `EventLog.append` 同一把锁)并读最新一份技能目录快照(没有为 undefined)。
|
|
316
320
|
* `db` is the caller's transaction handle (`KernelDb.db` inside `@Transactional`).
|
|
317
|
-
* 「读最新 → 推出下一份 →
|
|
321
|
+
* 「读最新 → 推出下一份 → 追加」都在这把锁内,别的写快照的事务(运行开始、技能注册、拒绝时的回退)插不进来。
|
|
318
322
|
*/
|
|
319
323
|
export async function lockLatestCatalog(db, conversationId) {
|
|
320
324
|
await db
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { AgentsService } from "../agents/agents.service.js";
|
|
3
2
|
import { type Principal } from "../identity/principal.js";
|
|
4
3
|
import { InboxService, type InboxView } from "../inbox/inbox.service.js";
|
|
5
4
|
import { type OrgContext } from "../orgs/org.guard.js";
|
|
6
5
|
import { type SkillChangeDetail, SkillChangesService, type SkillChangeView } from "./changes.service.js";
|
|
7
|
-
import { type SkillSummary, SkillsService } from "./skills.service.js";
|
|
8
6
|
declare const DecideBody: z.ZodObject<{
|
|
9
7
|
decision: z.ZodEnum<{
|
|
10
8
|
approve: "approve";
|
|
@@ -16,9 +14,11 @@ declare const NoticeParamsSchema: z.ZodObject<{
|
|
|
16
14
|
id: z.ZodString;
|
|
17
15
|
}, z.core.$strip>;
|
|
18
16
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
17
|
+
* Skill change requests (`/api/v1/orgs/:orgId/skill-changes`): sharing an agent skill with the org
|
|
18
|
+
* and version proposals on a shared skill (spec §5.4, §5.5), user principals only (agents and
|
|
19
|
+
* service tokens never decide). `GET /:id` is `approvals.decide`; the service shows it to org
|
|
20
|
+
* admins and the requester only, anyone else 404. `POST /:id/decide` is `skills.manage` (org
|
|
21
|
+
* admins; the service re-checks the role live under the org row lock).
|
|
22
22
|
*/
|
|
23
23
|
export declare class SkillChangesController {
|
|
24
24
|
private readonly changes;
|
|
@@ -30,23 +30,6 @@ export declare class SkillChangesController {
|
|
|
30
30
|
skillChange: SkillChangeView;
|
|
31
31
|
}>;
|
|
32
32
|
}
|
|
33
|
-
/**
|
|
34
|
-
* agent 自己的技能(`/api/v1/orgs/:orgId/agents/:agentId/skills`,M5 T15 / T16):
|
|
35
|
-
* - `GET /`:列表(`scope=agent`、未删除,按名字),与 `GET /agents/:agentId` 同一可见性(`agents.use`;
|
|
36
|
-
* 看不到的 agent → 404 `agent.not_found`;服务令牌只看到 visibility='org' 的 agent);
|
|
37
|
-
* - `DELETE /:skillId`:软删除,只有该 agent 当前的负责人(其他人 403 `forbidden`),仅限用户主体
|
|
38
|
-
* (`agents.create` 属 HUMAN_ONLY)。同名的待处理改动一并取消。
|
|
39
|
-
*/
|
|
40
|
-
export declare class AgentSkillsController {
|
|
41
|
-
private readonly changes;
|
|
42
|
-
private readonly agents;
|
|
43
|
-
private readonly skills;
|
|
44
|
-
constructor(changes: SkillChangesService, agents: AgentsService, skills: SkillsService);
|
|
45
|
-
list(principal: Principal, org: OrgContext, agentId: string): Promise<{
|
|
46
|
-
skills: SkillSummary[];
|
|
47
|
-
}>;
|
|
48
|
-
remove(principal: Principal, org: OrgContext, agentId: string, skillId: string): Promise<void>;
|
|
49
|
-
}
|
|
50
33
|
/**
|
|
51
34
|
* 收件箱(`GET /api/v1/orgs/:orgId/inbox`,计划取舍 C6:按类型汇总):当前用户待处理的工具审批与
|
|
52
35
|
* 能决定的技能变更,新的在前、最多 100 项(`truncated` 表示还有更多)。仅限用户主体。
|
|
@@ -7,9 +7,8 @@ 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 { Controller,
|
|
10
|
+
import { Controller, Get, HttpCode, Inject, Param, Post } from "@nestjs/common";
|
|
11
11
|
import { z } from "zod";
|
|
12
|
-
import { AgentsService } from "../agents/agents.service.js";
|
|
13
12
|
import { CurrentPrincipal, patTokenId, requireUser, } from "../identity/principal.js";
|
|
14
13
|
import { InboxNoticeParams } from "../inbox/inbox.schemas.js";
|
|
15
14
|
import { InboxService } from "../inbox/inbox.service.js";
|
|
@@ -17,7 +16,6 @@ import { createZodDto } from "../infra/validation/create-zod-dto.js";
|
|
|
17
16
|
import { ZBody, ZParam } from "../infra/validation/zod-params.js";
|
|
18
17
|
import { CurrentOrg, OrgAction } from "../orgs/org.guard.js";
|
|
19
18
|
import { SkillChangesService, } from "./changes.service.js";
|
|
20
|
-
import { SkillsService } from "./skills.service.js";
|
|
21
19
|
const DecideBody = z
|
|
22
20
|
.object({
|
|
23
21
|
decision: z.enum(["approve", "reject"]),
|
|
@@ -30,9 +28,11 @@ const NoticeParamsSchema = InboxNoticeParams;
|
|
|
30
28
|
class NoticeParams extends createZodDto(NoticeParamsSchema, "InboxNoticeParams") {
|
|
31
29
|
}
|
|
32
30
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
31
|
+
* Skill change requests (`/api/v1/orgs/:orgId/skill-changes`): sharing an agent skill with the org
|
|
32
|
+
* and version proposals on a shared skill (spec §5.4, §5.5), user principals only (agents and
|
|
33
|
+
* service tokens never decide). `GET /:id` is `approvals.decide`; the service shows it to org
|
|
34
|
+
* admins and the requester only, anyone else 404. `POST /:id/decide` is `skills.manage` (org
|
|
35
|
+
* admins; the service re-checks the role live under the org row lock).
|
|
36
36
|
*/
|
|
37
37
|
let SkillChangesController = class SkillChangesController {
|
|
38
38
|
changes;
|
|
@@ -60,7 +60,7 @@ __decorate([
|
|
|
60
60
|
__decorate([
|
|
61
61
|
Post(":id/decide"),
|
|
62
62
|
HttpCode(200),
|
|
63
|
-
OrgAction("
|
|
63
|
+
OrgAction("skills.manage"),
|
|
64
64
|
__param(0, CurrentPrincipal()),
|
|
65
65
|
__param(1, CurrentOrg()),
|
|
66
66
|
__param(2, Param("id")),
|
|
@@ -71,54 +71,6 @@ SkillChangesController = __decorate([
|
|
|
71
71
|
__param(0, Inject(SkillChangesService))
|
|
72
72
|
], SkillChangesController);
|
|
73
73
|
export { SkillChangesController };
|
|
74
|
-
/**
|
|
75
|
-
* agent 自己的技能(`/api/v1/orgs/:orgId/agents/:agentId/skills`,M5 T15 / T16):
|
|
76
|
-
* - `GET /`:列表(`scope=agent`、未删除,按名字),与 `GET /agents/:agentId` 同一可见性(`agents.use`;
|
|
77
|
-
* 看不到的 agent → 404 `agent.not_found`;服务令牌只看到 visibility='org' 的 agent);
|
|
78
|
-
* - `DELETE /:skillId`:软删除,只有该 agent 当前的负责人(其他人 403 `forbidden`),仅限用户主体
|
|
79
|
-
* (`agents.create` 属 HUMAN_ONLY)。同名的待处理改动一并取消。
|
|
80
|
-
*/
|
|
81
|
-
let AgentSkillsController = class AgentSkillsController {
|
|
82
|
-
changes;
|
|
83
|
-
agents;
|
|
84
|
-
skills;
|
|
85
|
-
constructor(changes, agents, skills) {
|
|
86
|
-
this.changes = changes;
|
|
87
|
-
this.agents = agents;
|
|
88
|
-
this.skills = skills;
|
|
89
|
-
}
|
|
90
|
-
async list(principal, org, agentId) {
|
|
91
|
-
await this.agents.get(org.orgId, agentId, principal.kind === "user" ? principal.account.id : null);
|
|
92
|
-
return { skills: await this.skills.listForAgent(org.orgId, agentId) };
|
|
93
|
-
}
|
|
94
|
-
async remove(principal, org, agentId, skillId) {
|
|
95
|
-
const p = requireUser(principal);
|
|
96
|
-
await this.changes.deleteAgentSkill(org.orgId, agentId, skillId, p.account.id, patTokenId(p));
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
__decorate([
|
|
100
|
-
Get(),
|
|
101
|
-
OrgAction("agents.use"),
|
|
102
|
-
__param(0, CurrentPrincipal()),
|
|
103
|
-
__param(1, CurrentOrg()),
|
|
104
|
-
__param(2, Param("agentId"))
|
|
105
|
-
], AgentSkillsController.prototype, "list", null);
|
|
106
|
-
__decorate([
|
|
107
|
-
Delete(":skillId"),
|
|
108
|
-
HttpCode(204),
|
|
109
|
-
OrgAction("agents.create"),
|
|
110
|
-
__param(0, CurrentPrincipal()),
|
|
111
|
-
__param(1, CurrentOrg()),
|
|
112
|
-
__param(2, Param("agentId")),
|
|
113
|
-
__param(3, Param("skillId"))
|
|
114
|
-
], AgentSkillsController.prototype, "remove", null);
|
|
115
|
-
AgentSkillsController = __decorate([
|
|
116
|
-
Controller("api/v1/orgs/:orgId/agents/:agentId/skills"),
|
|
117
|
-
__param(0, Inject(SkillChangesService)),
|
|
118
|
-
__param(1, Inject(AgentsService)),
|
|
119
|
-
__param(2, Inject(SkillsService))
|
|
120
|
-
], AgentSkillsController);
|
|
121
|
-
export { AgentSkillsController };
|
|
122
74
|
/**
|
|
123
75
|
* 收件箱(`GET /api/v1/orgs/:orgId/inbox`,计划取舍 C6:按类型汇总):当前用户待处理的工具审批与
|
|
124
76
|
* 能决定的技能变更,新的在前、最多 100 项(`truncated` 表示还有更多)。仅限用户主体。
|
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
import { EventLog } from "../conversations/event-log.js";
|
|
2
|
-
import type { SkillManifest } from "../db/kernel-schema.js";
|
|
3
2
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
4
3
|
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
5
4
|
import type { KernelLogger } from "../log.js";
|
|
5
|
+
import { OrgLock } from "../orgs/org-lock.js";
|
|
6
6
|
import { StorageService } from "../storage/storage.service.js";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
*/
|
|
11
|
-
export declare const AGENT_SKILLS_MAX = 50;
|
|
12
|
-
/** 收件箱一次最多返回的技能变更数。 */
|
|
7
|
+
import { type CancelledDrafts } from "./conversation-catalog.js";
|
|
8
|
+
import { SkillsService } from "./skills.service.js";
|
|
9
|
+
export type { CancelledDrafts } from "./conversation-catalog.js";
|
|
10
|
+
/** The most skill changes one inbox read returns. */
|
|
13
11
|
export declare const SKILL_CHANGES_LIST_MAX = 100;
|
|
14
12
|
export type SkillChangeStatus = "pending" | "approved" | "rejected" | "cancelled";
|
|
15
|
-
/**
|
|
13
|
+
/** A request kind: sharing an agent skill with the org, or a new version of a shared skill. */
|
|
14
|
+
export type SkillChangeKind = "share" | "version";
|
|
15
|
+
/** One skill change request (list / inbox). */
|
|
16
16
|
export interface SkillChangeView {
|
|
17
17
|
id: string;
|
|
18
18
|
orgId: string;
|
|
19
|
+
kind: SkillChangeKind;
|
|
19
20
|
agent: {
|
|
20
21
|
id: string;
|
|
21
22
|
name: string;
|
|
22
23
|
};
|
|
23
|
-
/**
|
|
24
|
+
/** A share: the agent skill; a version proposal: the shared org skill. */
|
|
24
25
|
skillId: string | null;
|
|
25
26
|
name: string;
|
|
26
27
|
description: string;
|
|
27
|
-
/**
|
|
28
|
+
/** A share: the version shared; a version proposal: the version it would become. */
|
|
28
29
|
version: number;
|
|
29
30
|
files: {
|
|
30
31
|
path: string;
|
|
@@ -32,24 +33,26 @@ export interface SkillChangeView {
|
|
|
32
33
|
}[];
|
|
33
34
|
status: SkillChangeStatus;
|
|
34
35
|
requestedBy: string;
|
|
35
|
-
/**
|
|
36
|
+
/** The requester's display name (empty when the account no longer exists). */
|
|
36
37
|
requestedByName: string;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
/** The proposing conversation (null for a share request and a proposal made on the web). */
|
|
39
|
+
requestedInConversation: string | null;
|
|
40
|
+
/** The proposing conversation's web path (no locale prefix), or null. */
|
|
41
|
+
conversationPath: string | null;
|
|
40
42
|
decidedBy: string | null;
|
|
41
43
|
decidedAt: string | null;
|
|
42
44
|
createdAt: string;
|
|
43
45
|
}
|
|
44
|
-
/**
|
|
46
|
+
/** One file of a detail: its text, or null when it cannot be read (deleted, over the read cap). */
|
|
45
47
|
export interface SkillChangeFile {
|
|
46
48
|
path: string;
|
|
47
49
|
size: number;
|
|
48
50
|
content: string | null;
|
|
49
51
|
}
|
|
50
52
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
+
* The detail: each file with its text (null when the draft is deleted); `current` is the version
|
|
54
|
+
* in effect when the request changes an existing skill (the web shows the difference), null for a
|
|
55
|
+
* share (the shared version is the current one) or when the skill is deleted.
|
|
53
56
|
*/
|
|
54
57
|
export interface SkillChangeDetail extends Omit<SkillChangeView, "files"> {
|
|
55
58
|
files: SkillChangeFile[];
|
|
@@ -58,53 +61,20 @@ export interface SkillChangeDetail extends Omit<SkillChangeView, "files"> {
|
|
|
58
61
|
files: SkillChangeFile[];
|
|
59
62
|
} | null;
|
|
60
63
|
}
|
|
61
|
-
/** {@link SkillChangesService.write} 的调用上下文(来自工具调用)。 */
|
|
62
|
-
export interface SkillWriteContext {
|
|
63
|
-
orgId: string;
|
|
64
|
-
agentId: string;
|
|
65
|
-
/** 触发本次运行的人。 */
|
|
66
|
-
accountId: string;
|
|
67
|
-
conversationId: string;
|
|
68
|
-
runId?: string;
|
|
69
|
-
}
|
|
70
|
-
/** 已合成、已校验的技能(见 tools/builtins/skill-write.ts 的 `buildSkillWrite`)。 */
|
|
71
|
-
export interface SkillWritePackage {
|
|
72
|
-
name: string;
|
|
73
|
-
description: string;
|
|
74
|
-
files: {
|
|
75
|
-
path: string;
|
|
76
|
-
data: Uint8Array;
|
|
77
|
-
size: number;
|
|
78
|
-
}[];
|
|
79
|
-
manifest: SkillManifest;
|
|
80
|
-
}
|
|
81
|
-
/** 写技能的结果:私有 agent 直接生成版本,共享 agent 生成变更申请。 */
|
|
82
|
-
export type SkillWriteOutcome = {
|
|
83
|
-
kind: "version";
|
|
84
|
-
skillId: string;
|
|
85
|
-
version: number;
|
|
86
|
-
created: boolean;
|
|
87
|
-
} | {
|
|
88
|
-
kind: "requested";
|
|
89
|
-
requestId: string;
|
|
90
|
-
skillId: string;
|
|
91
|
-
version: number;
|
|
92
|
-
};
|
|
93
|
-
/** 被取消的草稿:提交后要删的对象前缀与要发布的(对话, seq)。 */
|
|
94
|
-
export interface CancelledDrafts {
|
|
95
|
-
prefixes: string[];
|
|
96
|
-
seqs: [string, number][];
|
|
97
|
-
}
|
|
98
64
|
/**
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
* - `decide
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
65
|
+
* Skill change requests decided by org admins (spec §5.4, §5.5): an agent's owner asks to share
|
|
66
|
+
* one of its skills with the org (`kind = 'share'`, created by `AgentSkillsService.share`), and
|
|
67
|
+
* the maintainer of a shared skill proposes a new version of it (`kind = 'version'`, created by
|
|
68
|
+
* `AgentSkillsService.register`).
|
|
69
|
+
* - `decide` (HTTP, human only; org admins, role read live under the org row lock): approving a
|
|
70
|
+
* share makes the skill an org skill with the requester as maintainer; approving a version
|
|
71
|
+
* writes it as the org skill's next version (`SkillsService.createVersionFromFiles`, the draft
|
|
72
|
+
* prefix becomes the version's) so every agent using it gets it at its next run start;
|
|
73
|
+
* rejecting a version deletes its draft and reverts the proposing conversation's trial; a share
|
|
74
|
+
* keeps its files whatever happens. A request that no longer applies (its agent deleted or
|
|
75
|
+
* transferred, its skill deleted or already moved) is cancelled instead.
|
|
76
|
+
* State is in PG (the org row lock serializes decisions), files in object storage
|
|
77
|
+
* `kernel/<orgId>/skills/<id>/`; no in-process state.
|
|
108
78
|
*/
|
|
109
79
|
export declare class SkillChangesService {
|
|
110
80
|
private readonly db;
|
|
@@ -112,74 +82,58 @@ export declare class SkillChangesService {
|
|
|
112
82
|
private readonly eventLog;
|
|
113
83
|
private readonly log;
|
|
114
84
|
readonly txHost: TransactionHost;
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
|
|
85
|
+
private readonly orgLock;
|
|
86
|
+
/** An approved version is an org skill version. */
|
|
87
|
+
private readonly skills;
|
|
88
|
+
private readonly catalogDeps;
|
|
89
|
+
constructor(db: KernelDb, storage: StorageService, eventLog: EventLog, log: KernelLogger, txHost: TransactionHost, orgLock: OrgLock,
|
|
90
|
+
/** An approved version is an org skill version. */
|
|
91
|
+
skills: SkillsService);
|
|
118
92
|
/**
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
93
|
+
* An org admin decides a request (see the class comment): not an org admin -> 403 `forbidden`;
|
|
94
|
+
* already decided -> 409 `skill_change.already_decided`; not in this org -> 404. Approving
|
|
95
|
+
* re-checks `customSkills` (403 `catalog.custom_disabled`) and, for a share, the name (409
|
|
96
|
+
* `skill.name_exists`; the request stays pending). A share whose skill has a newer version than
|
|
97
|
+
* the one reviewed is cancelled, never shared. Audit `skill.change_decided` (and
|
|
98
|
+
* `skill.shared`). Of concurrent decisions one wins, the others get `already_decided`.
|
|
123
99
|
*/
|
|
124
100
|
decide(orgId: string, id: string, accountId: string, body: {
|
|
125
101
|
decision: "approve" | "reject";
|
|
126
102
|
note?: string | undefined;
|
|
127
103
|
}, actorTokenId?: string): Promise<SkillChangeView>;
|
|
104
|
+
/** A version draft's files as a package (as registered), or 503 when one cannot be read. */
|
|
105
|
+
private readDraft;
|
|
128
106
|
/**
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
107
|
+
* The transaction of {@link decide}. Lock order: org row (FOR NO KEY UPDATE, role re-checked) -> agent
|
|
108
|
+
* row -> the proposing conversation (a version's revert appends there) -> skill row -> request
|
|
109
|
+
* row, the order registration and sharing use.
|
|
132
110
|
*/
|
|
133
|
-
deleteAgentSkill(orgId: string, agentId: string, skillId: string, accountId: string, actorTokenId?: string, auditDetail?: Record<string, unknown>): Promise<void>;
|
|
134
|
-
/** The transaction of {@link write}. */
|
|
135
|
-
private writeIn;
|
|
136
|
-
/** The transaction of {@link decide}. */
|
|
137
111
|
private decideIn;
|
|
138
|
-
|
|
139
|
-
private deleteAgentSkillIn;
|
|
140
|
-
/** 当前用户(作为 agent 负责人)能决定的待处理申请,新的在前,最多 {@link SKILL_CHANGES_LIST_MAX} 条。 */
|
|
141
|
-
listPending(orgId: string, accountId: string): Promise<SkillChangeView[]>;
|
|
112
|
+
private reread;
|
|
142
113
|
/**
|
|
143
|
-
*
|
|
144
|
-
*
|
|
114
|
+
* The org's pending requests when the account is an org admin (read live; anyone else gets
|
|
115
|
+
* none), newest first, at most {@link SKILL_CHANGES_LIST_MAX}.
|
|
145
116
|
*/
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* 在事务 `t` 里由对话最新一份快照推出下一份并追加(不同才写):先锁会话行(与 `EventLog.append` 同一把锁),
|
|
149
|
-
* 锁内读最新快照,保证「读最新 → 追加」之间没有别的快照插进来。返回写入的 seq,没写返回 null。
|
|
150
|
-
* Phase B: `derive` gets the whole latest payload, so `pinned` and `toolMap` are carried forward;
|
|
151
|
-
* a pinned entry is kept only while `skills` has the same id, version and source (pinned ⊆
|
|
152
|
-
* skills), and the pinned bodies still fit the size limit. The tool map is only recomputed at run
|
|
153
|
-
* start.
|
|
154
|
-
*/
|
|
155
|
-
private appendCatalog;
|
|
117
|
+
listPending(orgId: string, accountId: string): Promise<SkillChangeView[]>;
|
|
156
118
|
/**
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
* 移除时不推测同名的组织技能(快照里已被替换掉),下一次运行开始的解析会把它补回来。
|
|
119
|
+
* The detail (with file texts): only org admins and the requester see it, anyone else 404 (the
|
|
120
|
+
* request's existence is not disclosed). A version draft's contents are null once it is deleted
|
|
121
|
+
* (rejected / cancelled); a share's files are the skill version's own and stay readable.
|
|
161
122
|
*/
|
|
162
|
-
|
|
123
|
+
get(orgId: string, id: string, accountId: string): Promise<SkillChangeDetail>;
|
|
163
124
|
/**
|
|
164
|
-
* In the caller's transaction (`mandatory`: `AgentsService
|
|
165
|
-
*
|
|
166
|
-
* appends a reverting snapshot to each
|
|
167
|
-
*
|
|
125
|
+
* In the caller's transaction (`mandatory`: `AgentsService` holds the org and agent row locks),
|
|
126
|
+
* cancels the agent's pending requests of the given kinds (default both): marks them
|
|
127
|
+
* cancelled, audits, and for version drafts appends a reverting snapshot to each proposing
|
|
128
|
+
* conversation. The agent's delete cancels both kinds; an ownership transfer only shares (the
|
|
129
|
+
* new owner did not ask). After the commit the caller runs {@link finishCancel} to delete the
|
|
130
|
+
* drafts and publish the events.
|
|
168
131
|
*/
|
|
169
|
-
cancelPendingForAgent(orgId: string, agentId: string, actorAccountId: string, reason: string, actorTokenId?: string): Promise<CancelledDrafts>;
|
|
170
|
-
/** {@link cancelPendingForAgent}
|
|
132
|
+
cancelPendingForAgent(orgId: string, agentId: string, actorAccountId: string, reason: string, actorTokenId?: string, kinds?: readonly SkillChangeKind[]): Promise<CancelledDrafts>;
|
|
133
|
+
/** After {@link cancelPendingForAgent} commits: publishes the events, deletes the drafts. */
|
|
171
134
|
finishCancel(orgId: string, c: CancelledDrafts): Promise<void>;
|
|
172
|
-
/**
|
|
173
|
-
private assertBelowCap;
|
|
174
|
-
/** 写一个版本并让 `current_version` 指向它(技能不存在则新建)。 */
|
|
175
|
-
private createVersion;
|
|
176
|
-
/**
|
|
177
|
-
* 先给组织行加 KEY SHARE 锁,再锁 agent 行:与 `AgentsService`(组织行 FOR UPDATE → agent 行)同一顺序。
|
|
178
|
-
* 不先锁的话,本事务持有 agent 行后插入引用组织的行(外键取 KEY SHARE)会与之互相等待(40P01)。
|
|
179
|
-
*/
|
|
180
|
-
private keyShareOrg;
|
|
181
|
-
/** 尽力删除草稿对象(失败只记日志:孤儿对象随组织数据清理删除)。 */
|
|
135
|
+
/** Deletes draft objects best effort (a failure is only logged: org data cleanup removes them). */
|
|
182
136
|
private deletePrefix;
|
|
183
|
-
/**
|
|
137
|
+
/** Adds the agent names and requester names. */
|
|
184
138
|
private views;
|
|
185
139
|
}
|