@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.
Files changed (141) hide show
  1. package/bootstrap.json +25 -25
  2. package/dist/admin/admin-agents.controller.d.ts +28 -0
  3. package/dist/admin/admin-agents.controller.js +79 -0
  4. package/dist/admin/admin-connectors.controller.d.ts +29 -0
  5. package/dist/admin/admin-connectors.controller.js +79 -0
  6. package/dist/admin/admin-items.schemas.d.ts +42 -0
  7. package/dist/admin/admin-items.schemas.js +48 -0
  8. package/dist/admin/admin.controller.d.ts +11 -20
  9. package/dist/admin/admin.controller.js +28 -34
  10. package/dist/admin/admin.module.d.ts +4 -1
  11. package/dist/admin/admin.module.js +50 -4
  12. package/dist/admin/admin.schemas.d.ts +4 -0
  13. package/dist/admin/admin.schemas.js +4 -1
  14. package/dist/admin/audit.controller.d.ts +14 -0
  15. package/dist/admin/audit.controller.js +42 -0
  16. package/dist/admin/audit.schemas.d.ts +8 -0
  17. package/dist/admin/audit.schemas.js +17 -0
  18. package/dist/admin/health.service.d.ts +104 -0
  19. package/dist/admin/health.service.js +246 -0
  20. package/dist/admin/overview.controller.d.ts +31 -0
  21. package/dist/admin/overview.controller.js +78 -0
  22. package/dist/admin/overview.schemas.d.ts +8 -0
  23. package/dist/admin/overview.schemas.js +13 -0
  24. package/dist/admin/overview.service.d.ts +112 -0
  25. package/dist/admin/overview.service.js +223 -0
  26. package/dist/admin/platform-audit.service.d.ts +41 -0
  27. package/dist/admin/platform-audit.service.js +70 -0
  28. package/dist/admin/usage.service.d.ts +149 -0
  29. package/dist/admin/usage.service.js +321 -0
  30. package/dist/agents/admin-agents.d.ts +92 -0
  31. package/dist/agents/admin-agents.js +170 -0
  32. package/dist/agents/agents.module.d.ts +4 -3
  33. package/dist/agents/agents.module.js +7 -3
  34. package/dist/agents/agents.service.d.ts +41 -3
  35. package/dist/agents/agents.service.js +113 -27
  36. package/dist/agents/definition.d.ts +16 -0
  37. package/dist/agents/definition.js +32 -2
  38. package/dist/agents/org-templates.js +4 -0
  39. package/dist/background/launch.d.ts +1 -1
  40. package/dist/background/launch.js +3 -3
  41. package/dist/background/tasks.service.d.ts +35 -3
  42. package/dist/background/tasks.service.js +91 -36
  43. package/dist/catalog/catalog.module.js +8 -2
  44. package/dist/channels/channels.module.js +11 -2
  45. package/dist/channels/supervisor.d.ts +2 -0
  46. package/dist/channels/supervisor.js +4 -0
  47. package/dist/conversations/events.js +1 -1
  48. package/dist/conversations/titles.js +4 -8
  49. package/dist/db/kernel-schema.d.ts +8 -1
  50. package/dist/devices/devices.module.js +5 -2
  51. package/dist/errors.d.ts +22 -2
  52. package/dist/errors.js +22 -2
  53. package/dist/evals/evals.module.js +11 -2
  54. package/dist/extensions/permission-view.js +3 -3
  55. package/dist/http/api.module.js +10 -1
  56. package/dist/identity/settings.js +3 -2
  57. package/dist/identity/write-actor.d.ts +11 -0
  58. package/dist/identity/write-actor.js +7 -0
  59. package/dist/inbox/inbox.service.d.ts +2 -1
  60. package/dist/inbox/platform-inbox.service.d.ts +7 -1
  61. package/dist/inbox/platform-inbox.service.js +20 -2
  62. package/dist/infra/presence/presence.module.d.ts +6 -0
  63. package/dist/infra/presence/presence.module.js +22 -0
  64. package/dist/infra/presence/replica-presence.d.ts +87 -0
  65. package/dist/infra/presence/replica-presence.js +189 -0
  66. package/dist/kernel.module.js +3 -0
  67. package/dist/lifecycle/kernel-lifecycle.d.ts +3 -1
  68. package/dist/lifecycle/kernel-lifecycle.js +17 -3
  69. package/dist/local-devices/local-device-gateway.d.ts +6 -0
  70. package/dist/local-devices/local-device-gateway.js +12 -0
  71. package/dist/overrides.d.ts +7 -1
  72. package/dist/overrides.js +4 -0
  73. package/dist/platform/exclusions.js +15 -0
  74. package/dist/platform/operation.d.ts +1 -1
  75. package/dist/platform/operation.js +1 -1
  76. package/dist/platform/ops/admin-items.ops.d.ts +37 -0
  77. package/dist/platform/ops/admin-items.ops.js +278 -0
  78. package/dist/platform/ops/admin.ops.d.ts +10 -10
  79. package/dist/platform/ops/admin.ops.js +111 -42
  80. package/dist/platform/ops/agent-skills.ops.d.ts +29 -3
  81. package/dist/platform/ops/agent-skills.ops.js +290 -7
  82. package/dist/platform/ops/inbox.ops.js +7 -4
  83. package/dist/platform/ops/platform.ops.js +1 -1
  84. package/dist/platform/ops/skills.ops.js +1 -57
  85. package/dist/platform/platform-ops.module.d.ts +2 -1
  86. package/dist/platform/platform-ops.module.js +5 -0
  87. package/dist/platform/route-schemas.js +8 -0
  88. package/dist/roles/gateway-role.d.ts +4 -0
  89. package/dist/roles/gateway-role.js +8 -0
  90. package/dist/runtime/run-jobs.js +4 -2
  91. package/dist/sandbox/sandbox-file-reader.d.ts +35 -0
  92. package/dist/sandbox/sandbox-file-reader.js +98 -0
  93. package/dist/skills/agent-skills.controller.d.ts +48 -0
  94. package/dist/skills/agent-skills.controller.js +131 -0
  95. package/dist/skills/agent-skills.service.d.ts +262 -0
  96. package/dist/skills/agent-skills.service.js +996 -0
  97. package/dist/skills/catalog.d.ts +8 -6
  98. package/dist/skills/catalog.js +8 -4
  99. package/dist/skills/changes.controller.d.ts +5 -22
  100. package/dist/skills/changes.controller.js +7 -55
  101. package/dist/skills/changes.service.d.ts +69 -115
  102. package/dist/skills/changes.service.js +249 -599
  103. package/dist/skills/conversation-catalog.d.ts +53 -0
  104. package/dist/skills/conversation-catalog.js +149 -0
  105. package/dist/skills/invocation-keys.d.ts +1 -1
  106. package/dist/skills/invocation-keys.js +1 -1
  107. package/dist/skills/package.d.ts +0 -5
  108. package/dist/skills/package.js +0 -14
  109. package/dist/skills/skills.controller.js +1 -10
  110. package/dist/skills/skills.module.js +15 -2
  111. package/dist/skills/skills.schemas.d.ts +11 -15
  112. package/dist/skills/skills.schemas.js +27 -20
  113. package/dist/skills/skills.service.d.ts +37 -30
  114. package/dist/skills/skills.service.js +107 -59
  115. package/dist/skills/usable.d.ts +4 -3
  116. package/dist/skills/usable.js +13 -4
  117. package/dist/tools/admin-connectors.d.ts +69 -0
  118. package/dist/tools/admin-connectors.js +135 -0
  119. package/dist/tools/builtin-names.d.ts +9 -14
  120. package/dist/tools/builtin-names.js +13 -22
  121. package/dist/tools/builtins/builtin-tools.d.ts +2 -3
  122. package/dist/tools/builtins/builtin-tools.js +21 -26
  123. package/dist/tools/builtins/sandbox/bash.js +2 -2
  124. package/dist/tools/builtins/skill-load.js +1 -0
  125. package/dist/tools/connectors.controller.d.ts +5 -1
  126. package/dist/tools/connectors.controller.js +17 -3
  127. package/dist/tools/connectors.service.d.ts +20 -1
  128. package/dist/tools/connectors.service.js +61 -0
  129. package/dist/tools/legacy-keys.js +0 -1
  130. package/dist/tools/org-tool-switches.d.ts +3 -2
  131. package/dist/tools/org-tool-switches.js +4 -4
  132. package/dist/tools/policy.d.ts +7 -9
  133. package/dist/tools/policy.js +11 -22
  134. package/dist/tools/tools.module.js +3 -0
  135. package/package.json +1 -1
  136. package/src/migrations/0109_audit_platform_idx.sql +5 -0
  137. package/src/migrations/0110_usage_time_idx.sql +8 -0
  138. package/src/migrations/0111_agent_skill_sharing.sql +22 -0
  139. package/src/migrations/0112_skill_share_requests.sql +4 -0
  140. package/dist/tools/builtins/skill-write.d.ts +0 -59
  141. package/dist/tools/builtins/skill-write.js +0 -244
@@ -29,8 +29,8 @@ export interface EffectiveSkillsInput {
29
29
  /** 本次运行固定的 agent 版本的定义(`skills.orgSkills` 是选中的组织技能 id)。 */
30
30
  agent: Pick<AgentDefinition, "skills">;
31
31
  /**
32
- * 对话 id:共享 agent 待批准的技能改动(T15,`skill_change_requests`)只在发起它的对话里生效(试用),
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
- * 试用(T15,R4):这个 agent 待批准、且由本对话发起的技能改动,按名字替换对应技能的版本 / 新增技能
46
- * (id 为已有技能或预先分配的 id,版本为批准后预期的版本号);其他对话照旧用 `current_version`。
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
- * 「读最新 → 推出下一份 → 追加」都在这把锁内,别的写快照的事务(运行开始、SkillWrite、拒绝时的回退)插不进来。
130
+ * 「读最新 → 推出下一份 → 追加」都在这把锁内,别的写快照的事务(运行开始、技能注册、拒绝时的回退)插不进来。
129
131
  */
130
132
  export declare function lockLatestCatalog(db: KernelSchemaDb, conversationId: string): Promise<SkillsSnapshot | undefined>;
131
133
  /**
@@ -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
- * 试用(T15,R4):这个 agent 待批准、且由本对话发起的技能改动,按名字替换对应技能的版本 / 新增技能
44
- * (id 为已有技能或预先分配的 id,版本为批准后预期的版本号);其他对话照旧用 `current_version`。
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
- * 「读最新 → 推出下一份 → 追加」都在这把锁内,别的写快照的事务(运行开始、SkillWrite、拒绝时的回退)插不进来。
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
- * 共享 agent 的技能变更申请(`/api/v1/orgs/:orgId/skill-changes`,M5 T15,R4)。动作 `approvals.decide`
20
- * (访客起、仅限用户主体:agent / 服务令牌不能决定,R2);能否决定由服务按该 agent **当前的负责人**判定,
21
- * 其他人 403 `skill_change.not_owner`。详情只给负责人与发起人,其他人 404。
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, Delete, Get, HttpCode, Inject, Param, Post } from "@nestjs/common";
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
- * 共享 agent 的技能变更申请(`/api/v1/orgs/:orgId/skill-changes`,M5 T15,R4)。动作 `approvals.decide`
34
- * (访客起、仅限用户主体:agent / 服务令牌不能决定,R2);能否决定由服务按该 agent **当前的负责人**判定,
35
- * 其他人 403 `skill_change.not_owner`。详情只给负责人与发起人,其他人 404。
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("approvals.decide"),
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
- * 每个 agent 自己的技能(`scope = agent`)上限,含待批准的新技能。远低于目录快照的上限(`SKILLS_CATALOG_MAX`),
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
- /** 已有技能的 id;新技能为 null(批准后才有)。 */
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
- requestedInConversation: string;
38
- /** 网页中发起对话的路径(不含语言前缀)。 */
39
- conversationPath: string;
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
- /** 详情里的一个文件:文本内容读不到(已删除、超出读取上限)时为 null。 */
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
- * 详情:每个文件附文本内容(草稿已删除时为 null);`current` 是改动已有技能时该技能当前生效的版本
52
- * (网页据此显示差异),新技能或技能已删除时为 null。
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
- * agent 自写技能与共享 agent 的技能变更审批(M5 T15,R4):
100
- * - `write`(工具 `SkillWrite` 调用):私有 agent 直接生成新版本;共享 agent 生成一条待负责人批准的申请,
101
- * 期间只有发起对话试用(`resolveEffectiveSkills` 按对话合并);两种情况都在同一事务里往发起对话追加一份
102
- * 技能目录快照(Ruling M17:日志是唯一事实源),同一运行的下一步即可 `Skill`;
103
- * - `decide`(HTTP,只有该 agent 当前的负责人):批准 → 版本对所有对话生效(各对话下一次运行开始时写新快照);
104
- * 拒绝 → 删除草稿对象,发起对话下一次运行开始时目录回到当前版本;
105
- * - 同一 agent 的同名技能最多一条待处理申请:同一对话再写取代旧的(旧的 cancelled、草稿删除、技能 id 不变),
106
- * 别的对话再写被拒绝(英文说明)。
107
- * 状态都在 PG(agent 行锁串行化同一 agent 的写与决定),文件在对象存储 `kernel/<orgId>/skills/<id>/`;无进程内状态。
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
- constructor(db: KernelDb, storage: StorageService, eventLog: EventLog, log: KernelLogger, txHost: TransactionHost);
116
- /** 写技能(见类注释)。模型可见的失败抛 `ToolError`。 */
117
- write(ctx: SkillWriteContext, pkg: SkillWritePackage): Promise<SkillWriteOutcome>;
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
- * 负责人决定一条申请:只有该 agent 当前的负责人(实时读)能决定,其他人 → 403 `skill_change.not_owner`;
120
- * 已处理 → 409 `skill_change.already_decided`;agent 已删除或申请不在本组织 → 404。
121
- * 批准:在同一事务里新增版本(技能不存在则用预先分配的 id 新建)、`current_version` 指向它,草稿对象原样成为版本文件;
122
- * 拒绝:提交后删除草稿对象。审计 `skill.change_decided`。
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
- * 软删除 agent 自己的一个技能(只有该 agent 当前的负责人;其他人 403 `forbidden`):技能不存在 / 已删除 / 不属于该
130
- * agent → `skill.not_found`。同名的待处理改动一并取消(发起对话追加回退快照,提交后删草稿)。审计 `skill.deleted`。
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
- /** The transaction of {@link deleteAgentSkill}. */
139
- private deleteAgentSkillIn;
140
- /** 当前用户(作为 agent 负责人)能决定的待处理申请,新的在前,最多 {@link SKILL_CHANGES_LIST_MAX} 条。 */
141
- listPending(orgId: string, accountId: string): Promise<SkillChangeView[]>;
112
+ private reread;
142
113
  /**
143
- * 详情(含文件文本):只有该 agent 的负责人与发起人能看,其他人一律 404(不泄露存在)。
144
- * 草稿对象已删除(拒绝 / 取消)时文件内容为 null。
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
- get(orgId: string, id: string, accountId: string): Promise<SkillChangeDetail>;
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
- * 草稿不再生效(拒绝 / 取消)时,在事务 `t` 里给发起对话追加一份回退快照:由该对话最新一份快照推出——
158
- * 来源是这份草稿的条目换成这个 agent 技能当前的正式版本(`t` 里已是决定之后的状态),没有正式版本就移除。
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
- private revertTrial;
123
+ get(orgId: string, id: string, accountId: string): Promise<SkillChangeDetail>;
163
124
  /**
164
- * In the caller's transaction (`mandatory`: `AgentsService.softDelete` holds the org and agent
165
- * row locks), cancels every pending skill change of the agent: marks them cancelled, audits, and
166
- * appends a reverting snapshot to each requesting conversation. After the commit the caller runs
167
- * {@link finishCancel} to delete the drafts and publish the events.
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
- /** 新技能的数量上限(含待批准的新技能;`excluding` 是将被取代的申请)。 */
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
- /** 补齐 agent 名。 */
137
+ /** Adds the agent names and requester names. */
184
138
  private views;
185
139
  }