@capybara-hq/kernel 0.1.0-rc.3 → 0.1.0-rc.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/admin.controller.d.ts +9 -4
- package/dist/admin/admin.controller.js +13 -4
- package/dist/admin/extensions.controller.d.ts +8 -1
- package/dist/admin/extensions.controller.js +22 -2
- package/dist/agents/agent-lookup.d.ts +3 -0
- package/dist/agents/agent-lookup.js +10 -0
- package/dist/agents/agent-profile.service.d.ts +29 -0
- package/dist/agents/agent-profile.service.js +117 -0
- package/dist/agents/agents.controller.d.ts +93 -3
- package/dist/agents/agents.controller.js +114 -4
- package/dist/agents/agents.module.js +6 -2
- package/dist/agents/agents.service.d.ts +13 -5
- package/dist/agents/agents.service.js +30 -7
- package/dist/agents/definition.d.ts +4 -0
- package/dist/agents/definition.js +10 -0
- package/dist/agents/instruction-files.d.ts +60 -0
- package/dist/agents/instruction-files.js +111 -0
- package/dist/agents/models.controller.d.ts +9 -3
- package/dist/agents/models.controller.js +19 -4
- package/dist/agents/profile.d.ts +96 -0
- package/dist/agents/profile.js +51 -0
- package/dist/agents/readiness.controller.d.ts +26 -0
- package/dist/agents/readiness.controller.js +56 -0
- package/dist/agents/templates.js +1 -1
- package/dist/background/background.controller.d.ts +38 -0
- package/dist/background/background.controller.js +87 -0
- package/dist/background/background.module.d.ts +10 -0
- package/dist/background/background.module.js +32 -0
- package/dist/background/finish.d.ts +43 -0
- package/dist/background/finish.js +94 -0
- package/dist/background/launch-lock.d.ts +14 -0
- package/dist/background/launch-lock.js +39 -0
- package/dist/background/launch.d.ts +36 -0
- package/dist/background/launch.js +70 -0
- package/dist/background/poll.job.d.ts +53 -0
- package/dist/background/poll.job.js +182 -0
- package/dist/background/render.d.ts +23 -0
- package/dist/background/render.js +48 -0
- package/dist/background/session.d.ts +37 -0
- package/dist/background/session.js +66 -0
- package/dist/background/status.d.ts +35 -0
- package/dist/background/status.js +57 -0
- package/dist/background/stop.d.ts +62 -0
- package/dist/background/stop.js +225 -0
- package/dist/background/store.d.ts +150 -0
- package/dist/background/store.js +351 -0
- package/dist/background/store.module.d.ts +6 -0
- package/dist/background/store.module.js +22 -0
- package/dist/background/tasks.service.d.ts +67 -0
- package/dist/background/tasks.service.js +186 -0
- package/dist/background/wake-rules.d.ts +57 -0
- package/dist/background/wake-rules.js +83 -0
- package/dist/background/wake.d.ts +28 -0
- package/dist/background/wake.js +57 -0
- package/dist/catalog/claude/agents.js +2 -0
- package/dist/catalog/marketplaces.service.d.ts +1 -1
- package/dist/catalog/plugin-import.js +1 -1
- package/dist/catalog/plugin-upgrade.js +1 -1
- package/dist/channels/cards.js +1 -1
- package/dist/channels/connections.service.d.ts +16 -1
- package/dist/channels/connections.service.js +38 -4
- package/dist/channels/threads.d.ts +5 -0
- package/dist/channels/threads.js +8 -0
- package/dist/config/schema.d.ts +18 -0
- package/dist/config/schema.js +102 -0
- package/dist/conversations/access.js +2 -0
- package/dist/conversations/attachments.service.d.ts +30 -0
- package/dist/conversations/attachments.service.js +130 -5
- package/dist/conversations/conversations.controller.d.ts +36 -5
- package/dist/conversations/conversations.controller.js +62 -12
- package/dist/conversations/conversations.module.js +3 -0
- package/dist/conversations/conversations.service.d.ts +44 -2
- package/dist/conversations/conversations.service.js +140 -12
- package/dist/conversations/event-log.d.ts +1 -1
- package/dist/conversations/event-log.js +10 -1
- package/dist/conversations/events.d.ts +58 -0
- package/dist/conversations/events.js +57 -2
- package/dist/conversations/queue.d.ts +3 -1
- package/dist/conversations/queue.js +13 -2
- package/dist/conversations/queue.service.js +3 -1
- package/dist/conversations/titles.d.ts +7 -0
- package/dist/conversations/titles.js +15 -0
- package/dist/db/kernel-schema.d.ts +58 -2
- package/dist/db/pool.d.ts +5 -0
- package/dist/db/pool.js +3 -0
- package/dist/errors.d.ts +8 -0
- package/dist/errors.js +8 -0
- package/dist/evals/run-replay.d.ts +5 -2
- package/dist/evals/run-replay.js +30 -7
- package/dist/evals/step-replay.js +12 -6
- package/dist/evals/trajectory.js +1 -1
- package/dist/extensions/admin-ops.js +2 -0
- package/dist/extensions/admin-view.d.ts +3 -1
- package/dist/extensions/admin-view.js +10 -2
- package/dist/extensions/blobs.js +1 -0
- package/dist/extensions/config-issues.d.ts +13 -1
- package/dist/extensions/config-issues.js +22 -5
- package/dist/extensions/config-json-schema.d.ts +43 -7
- package/dist/extensions/config-json-schema.js +124 -58
- package/dist/extensions/deployment-config-store.d.ts +6 -0
- package/dist/extensions/deployment-config.d.ts +50 -3
- package/dist/extensions/deployment-config.js +125 -28
- package/dist/extensions/display-name.d.ts +22 -0
- package/dist/extensions/display-name.js +77 -0
- package/dist/extensions/extensions.module.js +6 -0
- package/dist/extensions/host.d.ts +26 -1
- package/dist/extensions/host.js +82 -9
- package/dist/extensions/org-config.controller.d.ts +11 -3
- package/dist/extensions/org-config.controller.js +14 -6
- package/dist/extensions/org-config.d.ts +6 -0
- package/dist/extensions/org-config.js +12 -13
- package/dist/extensions/package.d.ts +14 -1
- package/dist/extensions/package.js +51 -2
- package/dist/extensions/permission-view.d.ts +3 -0
- package/dist/extensions/point-defaults.controller.d.ts +34 -0
- package/dist/extensions/point-defaults.controller.js +71 -0
- package/dist/extensions/point-defaults.d.ts +64 -0
- package/dist/extensions/point-defaults.js +206 -0
- package/dist/extensions/registry.d.ts +1 -1
- package/dist/extensions/registry.js +2 -0
- package/dist/http/api.module.js +8 -0
- package/dist/http/nest-logger.d.ts +6 -5
- package/dist/http/nest-logger.js +24 -10
- package/dist/identity/auth.controller.js +9 -5
- package/dist/identity/cookies.d.ts +20 -5
- package/dist/identity/cookies.js +44 -6
- package/dist/identity/me.controller.d.ts +5 -1
- package/dist/identity/me.controller.js +12 -3
- package/dist/identity/sessions.d.ts +12 -0
- package/dist/identity/sessions.js +45 -0
- package/dist/index.d.ts +1 -1
- package/dist/infra/config/kernel-config.service.js +6 -0
- package/dist/infra/database/database.module.js +1 -0
- package/dist/infra/events/kernel-events.d.ts +8 -0
- package/dist/infra/lifecycle/process-guards.js +4 -0
- package/dist/infra/logging/logging.module.d.ts +4 -2
- package/dist/infra/logging/logging.module.js +24 -6
- package/dist/infra/queue/redis-connection.d.ts +6 -0
- package/dist/infra/queue/redis-connection.js +7 -0
- package/dist/infra/redis/redis.module.js +6 -2
- package/dist/infra/tokens.d.ts +6 -1
- package/dist/infra/tokens.js +6 -1
- package/dist/log.d.ts +13 -1
- package/dist/log.js +93 -17
- package/dist/models/purposes.d.ts +23 -0
- package/dist/models/purposes.js +31 -10
- package/dist/orgs/offboarding.d.ts +3 -1
- package/dist/orgs/offboarding.js +26 -16
- package/dist/orgs/settings.service.d.ts +5 -0
- package/dist/orgs/settings.service.js +13 -2
- package/dist/roles/worker.module.js +6 -0
- package/dist/runtime/context/build.d.ts +9 -7
- package/dist/runtime/context/build.js +27 -19
- package/dist/runtime/context/claude-tools.d.ts +2 -1
- package/dist/runtime/context/claude-tools.js +5 -4
- package/dist/runtime/context/compaction.js +4 -0
- package/dist/runtime/langgraph-loop.js +3 -2
- package/dist/runtime/loop.d.ts +4 -3
- package/dist/runtime/maintenance.d.ts +4 -2
- package/dist/runtime/maintenance.js +17 -5
- package/dist/runtime/model-call.d.ts +17 -1
- package/dist/runtime/model-call.js +3 -2
- package/dist/runtime/providers.d.ts +6 -0
- package/dist/runtime/providers.js +8 -0
- package/dist/runtime/run-queue.d.ts +25 -2
- package/dist/runtime/run-queue.js +129 -33
- package/dist/runtime/run-worker.js +16 -3
- package/dist/runtime/runtime.module.js +8 -3
- package/dist/runtime/step-log.d.ts +6 -0
- package/dist/runtime/step-log.js +16 -2
- package/dist/runtime/subagents/definition.js +3 -1
- package/dist/runtime/usage-report.d.ts +2 -1
- package/dist/runtime/usage-report.js +2 -1
- package/dist/runtime/waits.d.ts +8 -2
- package/dist/runtime/waits.js +37 -11
- package/dist/sandbox/sandbox.module.js +6 -1
- package/dist/sandbox/sandbox.service.d.ts +61 -3
- package/dist/sandbox/sandbox.service.js +141 -7
- package/dist/tools/approvals.service.js +2 -0
- package/dist/tools/builtin-names.d.ts +20 -2
- package/dist/tools/builtin-names.js +29 -2
- package/dist/tools/builtins/builtin-tools.d.ts +15 -1
- package/dist/tools/builtins/builtin-tools.js +34 -2
- package/dist/tools/builtins/sandbox/bash.d.ts +1 -1
- package/dist/tools/builtins/sandbox/bash.js +230 -3
- package/dist/tools/builtins/sandbox/common.d.ts +27 -4
- package/dist/tools/builtins/sandbox/common.js +7 -3
- package/dist/tools/builtins/sandbox/deliver.js +1 -1
- package/dist/tools/builtins/sandbox/index.d.ts +2 -0
- package/dist/tools/builtins/sandbox/index.js +6 -0
- package/dist/tools/builtins/sandbox/task-output.d.ts +63 -0
- package/dist/tools/builtins/sandbox/task-output.js +304 -0
- package/dist/tools/builtins/sandbox/task-stop.d.ts +10 -0
- package/dist/tools/builtins/sandbox/task-stop.js +112 -0
- package/dist/tools/builtins/web/errors.d.ts +8 -0
- package/dist/tools/builtins/web/errors.js +53 -0
- package/dist/tools/builtins/web/extract.d.ts +62 -0
- package/dist/tools/builtins/web/extract.js +267 -0
- package/dist/tools/builtins/web/fetch.d.ts +55 -0
- package/dist/tools/builtins/web/fetch.js +174 -0
- package/dist/tools/builtins/web/index.d.ts +13 -0
- package/dist/tools/builtins/web/index.js +12 -0
- package/dist/tools/builtins/web/page-cache.d.ts +25 -0
- package/dist/tools/builtins/web/page-cache.js +77 -0
- package/dist/tools/builtins/web/search.d.ts +25 -0
- package/dist/tools/builtins/web/search.js +209 -0
- package/dist/tools/builtins/web/url.d.ts +17 -0
- package/dist/tools/builtins/web/url.js +43 -0
- package/dist/tools/oauth/flow-paths.d.ts +1 -1
- package/dist/tools/oauth/flow-paths.js +1 -1
- package/dist/tools/pipeline.js +15 -0
- package/dist/tools/registry.d.ts +22 -3
- package/dist/tools/registry.js +26 -11
- package/dist/tools/tools.module.js +12 -0
- package/dist/tools/validate.js +1 -1
- package/package.json +3 -3
- package/src/migrations/0064_account_last_org.sql +7 -0
- package/src/migrations/0065_conversation_archive.sql +8 -0
- package/src/migrations/0066_extension_display_name.sql +4 -0
- package/src/migrations/0067_agent_profiles.sql +20 -0
- package/src/migrations/0068_agent_avatar_uploads.sql +7 -0
- package/src/migrations/0069_attachments_agent_idx.sql +3 -0
- package/src/migrations/0070_background_tasks.sql +37 -0
- package/src/migrations/0071_background_tasks_reserve.sql +6 -0
- package/src/migrations/0072_background_tasks_stopping.sql +5 -0
- package/src/migrations/0073_org_extension_point_defaults.sql +11 -0
package/dist/models/purposes.js
CHANGED
|
@@ -41,6 +41,11 @@ export const KERNEL_PURPOSES = [
|
|
|
41
41
|
{ purpose: "eval", kind: "chat", label: { zh: "评测评委", en: "Eval judge" } },
|
|
42
42
|
/** Conversation titles (UI refresh B); unmapped → the conversation's current chat model. */
|
|
43
43
|
{ purpose: "title", kind: "chat", label: { zh: "会话标题", en: "Conversation titles" } },
|
|
44
|
+
/**
|
|
45
|
+
* The `WebFetch` extraction call (web tools spec §5); unmapped → the calling conversation's
|
|
46
|
+
* current chat model (a sub-agent's call: the sub-agent's).
|
|
47
|
+
*/
|
|
48
|
+
{ purpose: "web_fetch", kind: "chat", label: { zh: "网页提取", en: "Web page extraction" } },
|
|
44
49
|
{
|
|
45
50
|
purpose: "subagent_fast",
|
|
46
51
|
kind: "chat",
|
|
@@ -254,6 +259,27 @@ let ModelPurposesService = class ModelPurposesService {
|
|
|
254
259
|
}
|
|
255
260
|
return view.effective;
|
|
256
261
|
}
|
|
262
|
+
/** The target a {@link chat} call on `purpose` uses: the mapping, else `fallback` when unmapped. */
|
|
263
|
+
async chatTarget(orgId, purpose, fallback) {
|
|
264
|
+
try {
|
|
265
|
+
return await this.resolve(orgId, purpose);
|
|
266
|
+
}
|
|
267
|
+
catch (e) {
|
|
268
|
+
if (!(e instanceof ApiError && e.code === "model.unconfigured") || !fallback)
|
|
269
|
+
throw e;
|
|
270
|
+
return fallback;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* The limits of the model a {@link chat} call on `purpose` would use now (the same mapping and
|
|
275
|
+
* `fallback` rule): its context window and output cap, so a caller can size its request (e.g.
|
|
276
|
+
* the `WebFetch` page) before the call. Fails as `chat` does before sending.
|
|
277
|
+
*/
|
|
278
|
+
async chatLimits(orgId, purpose, opts = {}) {
|
|
279
|
+
const target = await this.chatTarget(orgId, purpose, opts.fallback);
|
|
280
|
+
const { info } = await this.providers.resolve(target.model);
|
|
281
|
+
return { contextWindow: info.contextWindow, maxOutputTokens: info.maxOutputTokens };
|
|
282
|
+
}
|
|
257
283
|
/**
|
|
258
284
|
* 按用途发一次对话请求:解析映射、按目标模型的声明宽松处理参数(补默认值,与运行时一致),用 `consumeModelStream`
|
|
259
285
|
* 收完(只有流空闲看门狗)。输出上限取 `min(req.maxOutputTokens, 目标模型的 maxOutputTokens)`。
|
|
@@ -261,22 +287,17 @@ let ModelPurposesService = class ModelPurposesService {
|
|
|
261
287
|
* `opts.fallback`: the target used when the purpose is not mapped (`model.unconfigured`).
|
|
262
288
|
* `opts.beforeSend`: called with the resolved target and the final request just before sending;
|
|
263
289
|
* what it throws is thrown as is (a pre-send failure, e.g. a denied `model.request` hook).
|
|
290
|
+
* `opts.paramDefaults`: values for parameters the target does not set, kept only where the
|
|
291
|
+
* target model declares the key and the value fits it (e.g. `thinking: "off"` for a short call).
|
|
264
292
|
*/
|
|
265
293
|
async chat(orgId, purpose, req, signal, opts = {}) {
|
|
266
|
-
|
|
267
|
-
try {
|
|
268
|
-
target = await this.resolve(orgId, purpose);
|
|
269
|
-
}
|
|
270
|
-
catch (e) {
|
|
271
|
-
if (!(e instanceof ApiError && e.code === "model.unconfigured") || !opts.fallback)
|
|
272
|
-
throw e;
|
|
273
|
-
target = opts.fallback;
|
|
274
|
-
}
|
|
294
|
+
const target = await this.chatTarget(orgId, purpose, opts.fallback);
|
|
275
295
|
const { provider, info } = await this.providers.resolve(target.model);
|
|
276
296
|
const request = {
|
|
277
297
|
...req,
|
|
278
298
|
model: info.id,
|
|
279
|
-
|
|
299
|
+
// undeclared or unfitting defaults are dropped like any other parameter
|
|
300
|
+
params: sanitizeParams(info.parameters, { ...opts.paramDefaults, ...target.params }).value,
|
|
280
301
|
// 输出上限不超过目标模型自己的上限(与运行时 assembleModelRequest 一致)
|
|
281
302
|
maxOutputTokens: Math.min(req.maxOutputTokens, info.maxOutputTokens),
|
|
282
303
|
};
|
|
@@ -83,7 +83,9 @@ export declare class Offboarding {
|
|
|
83
83
|
* In the caller's transaction (`mandatory`: the caller holds the org row lock, order org row →
|
|
84
84
|
* membership, and did the "last owner" checks):
|
|
85
85
|
* 1. 删除成员关系(非成员 → `member.not_found`;删后组织没有 owner → `org.last_owner`),清空指向该组织的会话当前组织;
|
|
86
|
-
* 2.
|
|
86
|
+
* 2. Removal and directory offboarding revoke **every** session and personal token of the
|
|
87
|
+
* account (both are account-wide, so conservatively all); a person who leaves (`left`) keeps
|
|
88
|
+
* them, and the session's current org is cleared (the membership check ends the access);
|
|
87
89
|
* 3. 删除其在该组织所有连接器上的个人凭据;
|
|
88
90
|
* 4. 取消其作为处理人的 pending 审批与提问(写 cancelled 事件),记下此人在该组织进行中的运行(提交后中止);
|
|
89
91
|
* 5. 其负责的该组织 agent 转给组织所有者(最早加入的 owner)并置 `needs_reassignment = true`;
|
package/dist/orgs/offboarding.js
CHANGED
|
@@ -83,7 +83,9 @@ let Offboarding = class Offboarding {
|
|
|
83
83
|
* In the caller's transaction (`mandatory`: the caller holds the org row lock, order org row →
|
|
84
84
|
* membership, and did the "last owner" checks):
|
|
85
85
|
* 1. 删除成员关系(非成员 → `member.not_found`;删后组织没有 owner → `org.last_owner`),清空指向该组织的会话当前组织;
|
|
86
|
-
* 2.
|
|
86
|
+
* 2. Removal and directory offboarding revoke **every** session and personal token of the
|
|
87
|
+
* account (both are account-wide, so conservatively all); a person who leaves (`left`) keeps
|
|
88
|
+
* them, and the session's current org is cleared (the membership check ends the access);
|
|
87
89
|
* 3. 删除其在该组织所有连接器上的个人凭据;
|
|
88
90
|
* 4. 取消其作为处理人的 pending 审批与提问(写 cancelled 事件),记下此人在该组织进行中的运行(提交后中止);
|
|
89
91
|
* 5. 其负责的该组织 agent 转给组织所有者(最早加入的 owner)并置 `needs_reassignment = true`;
|
|
@@ -150,21 +152,29 @@ let Offboarding = class Offboarding {
|
|
|
150
152
|
.where("account_id", "=", accountId)
|
|
151
153
|
.where("current_org_id", "=", orgId)
|
|
152
154
|
.execute();
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
.
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
.
|
|
155
|
+
// A person who leaves keeps their sign-in and personal tokens: the org guard reads the
|
|
156
|
+
// membership on every request, so access to this org ends with the row above, and their other
|
|
157
|
+
// orgs keep working. Removal and directory offboarding revoke both (account-wide, conservative).
|
|
158
|
+
const revoke = reason !== "left";
|
|
159
|
+
const sessions = revoke
|
|
160
|
+
? await this.db
|
|
161
|
+
.updateTable("sessions")
|
|
162
|
+
.set({ revoked_at: sql `now()` })
|
|
163
|
+
.where("account_id", "=", accountId)
|
|
164
|
+
.where("revoked_at", "is", null)
|
|
165
|
+
.returning("id")
|
|
166
|
+
.execute()
|
|
167
|
+
: [];
|
|
168
|
+
const tokens = revoke
|
|
169
|
+
? await this.db
|
|
170
|
+
.updateTable("api_tokens")
|
|
171
|
+
.set({ revoked_at: sql `now()` })
|
|
172
|
+
.where("kind", "=", "personal")
|
|
173
|
+
.where("account_id", "=", accountId)
|
|
174
|
+
.where("revoked_at", "is", null)
|
|
175
|
+
.returning("id")
|
|
176
|
+
.execute()
|
|
177
|
+
: [];
|
|
168
178
|
// in this transaction (the approvals and questions services join it: `mandatory`)
|
|
169
179
|
const credentials = await this.credentials.clearAccount(orgId, accountId);
|
|
170
180
|
const approvals = await this.approvals.cancelPendingFor(orgId, accountId);
|
|
@@ -12,6 +12,7 @@ import { OrgLock } from "./org-lock.js";
|
|
|
12
12
|
* - `locale`:组织默认语言(`zh` / `en`,默认 en),机器人在 IM 里说的固定话术按它选择。
|
|
13
13
|
* - `sandboxToolPolicy`:沙箱工具的默认策略(M5 T8,默认 allow)。为 `ask` 时除只读的
|
|
14
14
|
* `Read` / `Glob` / `Grep` 外都需要审批(执行时实时读取)。
|
|
15
|
+
* - `wakeOnBackgroundTask`:组织对 `runtime.wakeOnBackgroundTask` 的覆盖(缺省跟随部署),见 {@link effectiveWakeOnBackgroundTask}。
|
|
15
16
|
* - `sandboxEgress`:组织的沙箱出站(Ruling M19 / D6),缺省跟随部署的 `sandbox.limits.egress` + `allowHosts`。
|
|
16
17
|
* 见 {@link effectiveSandboxEgress}。存量值非法时按 `none` 读(宁可断网,不悄悄放宽到部署默认)。
|
|
17
18
|
*/
|
|
@@ -49,6 +50,7 @@ export declare const OrgSettingsSchema: z.ZodObject<{
|
|
|
49
50
|
}>;
|
|
50
51
|
allowHosts: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
51
52
|
}, z.core.$strict>>>;
|
|
53
|
+
wakeOnBackgroundTask: z.ZodCatch<z.ZodOptional<z.ZodBoolean>>;
|
|
52
54
|
}, z.core.$strip>;
|
|
53
55
|
export type OrgSettings = z.infer<typeof OrgSettingsSchema>;
|
|
54
56
|
/** PATCH 体:只改给出的字段;未知字段 → 400。 */
|
|
@@ -65,6 +67,7 @@ export declare const OrgSettingsPatchSchema: z.ZodObject<{
|
|
|
65
67
|
allow: "allow";
|
|
66
68
|
ask: "ask";
|
|
67
69
|
}>>;
|
|
70
|
+
wakeOnBackgroundTask: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
|
|
68
71
|
sandboxEgress: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
69
72
|
mode: z.ZodEnum<{
|
|
70
73
|
allowlist: "allowlist";
|
|
@@ -81,6 +84,8 @@ export type DeploymentEgress = Pick<SandboxLimits, "egress" | "allowHosts">;
|
|
|
81
84
|
* (省略时用部署的),但部署是 `none` 时仍为 `none`(组织永远不比部署放得更开,部署改成 none 后存量设置也随之收紧)。
|
|
82
85
|
*/
|
|
83
86
|
export declare function effectiveSandboxEgress(deployment: DeploymentEgress, org: SandboxEgressSetting | undefined): DeploymentEgress;
|
|
87
|
+
/** Whether a finished background task wakes an idle conversation: the org's setting, else the deployment's. */
|
|
88
|
+
export declare function effectiveWakeOnBackgroundTask(deployment: boolean, org: OrgSettings["wakeOnBackgroundTask"]): boolean;
|
|
84
89
|
/**
|
|
85
90
|
* 组织实际生效的沙箱限额(C19 / Ruling M16):企业管理员的覆盖(部署设置 `sandboxLimitOverrides[orgId]`)
|
|
86
91
|
* 给出的 cpu / memoryMb 替换部署默认,未给的项、disk 与出站沿用 `deployment`。只在创建沙箱时读取。
|
|
@@ -25,6 +25,7 @@ import { OrgLock } from "./org-lock.js";
|
|
|
25
25
|
* - `locale`:组织默认语言(`zh` / `en`,默认 en),机器人在 IM 里说的固定话术按它选择。
|
|
26
26
|
* - `sandboxToolPolicy`:沙箱工具的默认策略(M5 T8,默认 allow)。为 `ask` 时除只读的
|
|
27
27
|
* `Read` / `Glob` / `Grep` 外都需要审批(执行时实时读取)。
|
|
28
|
+
* - `wakeOnBackgroundTask`:组织对 `runtime.wakeOnBackgroundTask` 的覆盖(缺省跟随部署),见 {@link effectiveWakeOnBackgroundTask}。
|
|
28
29
|
* - `sandboxEgress`:组织的沙箱出站(Ruling M19 / D6),缺省跟随部署的 `sandbox.limits.egress` + `allowHosts`。
|
|
29
30
|
* 见 {@link effectiveSandboxEgress}。存量值非法时按 `none` 读(宁可断网,不悄悄放宽到部署默认)。
|
|
30
31
|
*/
|
|
@@ -58,6 +59,8 @@ export const OrgSettingsSchema = z.object({
|
|
|
58
59
|
locale: z.enum(["zh", "en"]).default("en").catch("en"),
|
|
59
60
|
sandboxToolPolicy: z.enum(["allow", "ask"]).default("allow").catch("allow"),
|
|
60
61
|
sandboxEgress: SandboxEgressSettingSchema.optional().catch({ mode: "none" }),
|
|
62
|
+
/** Overrides `runtime.wakeOnBackgroundTask`; absent follows the deployment. */
|
|
63
|
+
wakeOnBackgroundTask: z.boolean().optional().catch(undefined),
|
|
61
64
|
});
|
|
62
65
|
/** PATCH 体:只改给出的字段;未知字段 → 400。 */
|
|
63
66
|
export const OrgSettingsPatchSchema = z
|
|
@@ -65,6 +68,8 @@ export const OrgSettingsPatchSchema = z
|
|
|
65
68
|
toolSearch: z.enum(["on", "off"]).optional(),
|
|
66
69
|
locale: z.enum(["zh", "en"]).optional(),
|
|
67
70
|
sandboxToolPolicy: z.enum(["allow", "ask"]).optional(),
|
|
71
|
+
/** null clears (follow the deployment again). */
|
|
72
|
+
wakeOnBackgroundTask: z.boolean().nullable().optional(),
|
|
68
73
|
/** null 清除(恢复跟随部署默认)。 */
|
|
69
74
|
sandboxEgress: SandboxEgressSettingSchema.nullable().optional(),
|
|
70
75
|
})
|
|
@@ -80,6 +85,10 @@ export function effectiveSandboxEgress(deployment, org) {
|
|
|
80
85
|
return { egress: "none", allowHosts: [] };
|
|
81
86
|
return { egress: "allowlist", allowHosts: [...(org.allowHosts ?? deployment.allowHosts)] };
|
|
82
87
|
}
|
|
88
|
+
/** Whether a finished background task wakes an idle conversation: the org's setting, else the deployment's. */
|
|
89
|
+
export function effectiveWakeOnBackgroundTask(deployment, org) {
|
|
90
|
+
return org ?? deployment;
|
|
91
|
+
}
|
|
83
92
|
/**
|
|
84
93
|
* 组织实际生效的沙箱限额(C19 / Ruling M16):企业管理员的覆盖(部署设置 `sandboxLimitOverrides[orgId]`)
|
|
85
94
|
* 给出的 cpu / memoryMb 替换部署默认,未给的项、disk 与出站沿用 `deployment`。只在创建沙箱时读取。
|
|
@@ -169,15 +178,17 @@ let OrgSettingsService = class OrgSettingsService {
|
|
|
169
178
|
const before = parseOrgSettings(stored);
|
|
170
179
|
const changes = Object.fromEntries(Object.entries(patch)
|
|
171
180
|
.filter(([, v]) => v !== undefined)
|
|
172
|
-
// null
|
|
181
|
+
// null clears sandboxEgress / wakeOnBackgroundTask: follow the deployment default again
|
|
173
182
|
.map(([k, v]) => [k, v === null ? undefined : v]));
|
|
174
183
|
const after = { ...before, ...changes };
|
|
175
184
|
if (after.sandboxEgress === undefined)
|
|
176
185
|
delete after.sandboxEgress;
|
|
186
|
+
if (after.wakeOnBackgroundTask === undefined)
|
|
187
|
+
delete after.wakeOnBackgroundTask;
|
|
177
188
|
if (sameSettings(before, after))
|
|
178
189
|
return before;
|
|
179
190
|
// 与存量合并:保留本版本不认识的键(清除的 sandboxEgress 不留在存量里)
|
|
180
|
-
const { sandboxEgress: _old, ...rest } = stored;
|
|
191
|
+
const { sandboxEgress: _old, wakeOnBackgroundTask: _oldWake, ...rest } = stored;
|
|
181
192
|
await this.db
|
|
182
193
|
.updateTable("orgs")
|
|
183
194
|
.set({ settings: JSON.stringify({ ...rest, ...after }) })
|
|
@@ -6,12 +6,15 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
6
6
|
};
|
|
7
7
|
var WorkerModule_1;
|
|
8
8
|
import { Module } from "@nestjs/common";
|
|
9
|
+
import { BackgroundModule } from "../background/background.module.js";
|
|
10
|
+
import { BackgroundTaskPollJob } from "../background/poll.job.js";
|
|
9
11
|
import { CatalogModule } from "../catalog/catalog.module.js";
|
|
10
12
|
import { CatalogJobs } from "../catalog/jobs.js";
|
|
11
13
|
import { ChannelsModule, ChannelWorkersModule } from "../channels/channels.module.js";
|
|
12
14
|
import { GatewayCheckJob } from "../channels/supervisor.js";
|
|
13
15
|
import { AttachmentsModule } from "../conversations/attachments.module.js";
|
|
14
16
|
import { AttachmentCleanupJob } from "../conversations/attachments.service.js";
|
|
17
|
+
import { EventLogModule } from "../conversations/event-log.js";
|
|
15
18
|
import { TitlesModule } from "../conversations/titles.js";
|
|
16
19
|
import { EvalWorkersModule } from "../evals/evals.module.js";
|
|
17
20
|
import { ExtensionsModule } from "../extensions/extensions.module.js";
|
|
@@ -59,6 +62,8 @@ let WorkerModule = WorkerModule_1 = class WorkerModule {
|
|
|
59
62
|
AttachmentsModule,
|
|
60
63
|
StorageModule,
|
|
61
64
|
SandboxModule,
|
|
65
|
+
BackgroundModule,
|
|
66
|
+
EventLogModule,
|
|
62
67
|
ToolsModule,
|
|
63
68
|
CatalogModule,
|
|
64
69
|
OrgsModule,
|
|
@@ -71,6 +76,7 @@ let WorkerModule = WorkerModule_1 = class WorkerModule {
|
|
|
71
76
|
AttachmentCleanupJob,
|
|
72
77
|
StoragePurgeJob,
|
|
73
78
|
SandboxSweepJobs,
|
|
79
|
+
BackgroundTaskPollJob,
|
|
74
80
|
ToolJobs,
|
|
75
81
|
CatalogJobs,
|
|
76
82
|
DirectoryScanJob,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ContentBlock, type ModelInfo, type ModelRequest, type ParamValue } from "@capybara-hq/plugin-sdk";
|
|
2
2
|
import type { AgentDefinition } from "../../agents/definition.js";
|
|
3
|
-
import type
|
|
3
|
+
import { type ConversationEvent, type EventPayload } from "../../conversations/events.js";
|
|
4
4
|
import type { ResolvedTool } from "../../tools/registry.js";
|
|
5
5
|
/**
|
|
6
6
|
* 平台行为规范(模型可见,英文)。短而通用(spec 6 原则 5);不放时间戳、会话 ID 等会变化的内容,
|
|
@@ -54,13 +54,14 @@ export interface BuildModelRequestInput {
|
|
|
54
54
|
model: ModelInfo;
|
|
55
55
|
step: number;
|
|
56
56
|
/**
|
|
57
|
-
* loop
|
|
58
|
-
*
|
|
59
|
-
* -
|
|
57
|
+
* loop 已吸收到的位置(R31):the largest seq of the absorbable events (`user_message` and
|
|
58
|
+
* `background_task_finished`, {@link isAbsorbable}) the loop took. 提供时:
|
|
59
|
+
* - seq 大于它的可吸收事件不进请求(运行中途到达、尚未被吸收的插话或后台任务结束,由后续步骤吸收或触发下一轮);
|
|
60
|
+
* - 每个可吸收事件放在**吸收它的那次模型调用**的位置:日志里第一个 `request.absorbedUpToSeq`
|
|
60
61
|
* 不小于它的 `model_call` 之前(没有该字段的旧 model_call 视为吸收了它之前的全部消息),
|
|
61
62
|
* 本次请求吸收的放在末尾。于是模型看到的历史只追加(插话不会插到已发送的回复之前),
|
|
62
63
|
* 且请求可由日志 + `model_call` 精确还原。
|
|
63
|
-
* 不提供时按 seq
|
|
64
|
+
* 不提供时按 seq 原样回放全部可吸收事件。
|
|
64
65
|
*/
|
|
65
66
|
absorbedUpToSeq?: number;
|
|
66
67
|
/**
|
|
@@ -231,10 +232,11 @@ export declare function summaryText(summary: string): string;
|
|
|
231
232
|
* - messages:最近一条摘要(若有)作为首条 user 消息,其后按 seq 回放 `coversUpToSeq` 之后的
|
|
232
233
|
* `user_message` / `assistant_message`(content 原样,含 opaque;aborted 的也回放;媒体引用按
|
|
233
234
|
* {@link resolveMedia} 换成 base64 或文字占位)/ `reminder`
|
|
234
|
-
* (`role: "system"
|
|
235
|
+
* (`role: "system"`,放在它所在的位置)/ `background_task_finished`(`role: "system"`, the text of
|
|
236
|
+
* {@link renderBackgroundFinished}, placed like a user_message);`tool_result` 事件还原为紧随其 assistant 消息之后的一条 user 消息
|
|
235
237
|
* (同一步的多个结果合并,按该 assistant 消息里 tool_call 的顺序;找不到对应调用的结果不进请求)。
|
|
236
238
|
* 其他事件不进请求。提供 `absorbedUpToSeq` 时,
|
|
237
|
-
*
|
|
239
|
+
* 尚未被吸收的可吸收事件不进请求,运行中途到达的放在吸收它的调用处(见 BuildModelRequestInput)。
|
|
238
240
|
* 只追加:新事件只会在 messages 末尾追加;唯一的前缀变化来自新的压缩摘要。
|
|
239
241
|
* `step` 与 `agentVersion` 不进请求内容(保证缓存前缀稳定),由调用方写入 `model_call` 事件。
|
|
240
242
|
*/
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { MEDIA_LIMITS, } from "@capybara-hq/plugin-sdk";
|
|
3
|
+
import { renderBackgroundFinished } from "../../background/render.js";
|
|
4
|
+
import { isAbsorbable, } from "../../conversations/events.js";
|
|
3
5
|
import { catalogText, isAlwaysLoaded } from "../../tools/builtins/tool-search.js";
|
|
4
6
|
import { LEGACY_CATALOG_HEADER, LEGACY_SKILL_TEXTS, usesLegacyToolNames } from "./legacy-text.js";
|
|
5
7
|
import { invokedSkillNames, invokedSkillsText, SKILL_TEXTS, skillsCatalogEvents, snapshotChangeText, snapshotCurrentText, snapshotSystemText, systemSkillsCatalog, } from "./skills.js";
|
|
@@ -330,10 +332,11 @@ export function summaryText(summary) {
|
|
|
330
332
|
* - messages:最近一条摘要(若有)作为首条 user 消息,其后按 seq 回放 `coversUpToSeq` 之后的
|
|
331
333
|
* `user_message` / `assistant_message`(content 原样,含 opaque;aborted 的也回放;媒体引用按
|
|
332
334
|
* {@link resolveMedia} 换成 base64 或文字占位)/ `reminder`
|
|
333
|
-
* (`role: "system"
|
|
335
|
+
* (`role: "system"`,放在它所在的位置)/ `background_task_finished`(`role: "system"`, the text of
|
|
336
|
+
* {@link renderBackgroundFinished}, placed like a user_message);`tool_result` 事件还原为紧随其 assistant 消息之后的一条 user 消息
|
|
334
337
|
* (同一步的多个结果合并,按该 assistant 消息里 tool_call 的顺序;找不到对应调用的结果不进请求)。
|
|
335
338
|
* 其他事件不进请求。提供 `absorbedUpToSeq` 时,
|
|
336
|
-
*
|
|
339
|
+
* 尚未被吸收的可吸收事件不进请求,运行中途到达的放在吸收它的调用处(见 BuildModelRequestInput)。
|
|
337
340
|
* 只追加:新事件只会在 messages 末尾追加;唯一的前缀变化来自新的压缩摘要。
|
|
338
341
|
* `step` 与 `agentVersion` 不进请求内容(保证缓存前缀稳定),由调用方写入 `model_call` 事件。
|
|
339
342
|
*/
|
|
@@ -378,7 +381,7 @@ export function buildModelRequest(input) {
|
|
|
378
381
|
lastCall = absorbedBy(e);
|
|
379
382
|
}
|
|
380
383
|
/**
|
|
381
|
-
* 第 i
|
|
384
|
+
* 第 i 个事件(可吸收事件:user_message / background_task_finished)的放置方式:
|
|
382
385
|
* - `inline`:在吸收它的调用(之后第一个 `absorbedBy ≥ seq` 的 model_call,或本次请求)之前,
|
|
383
386
|
* 没有「由未吸收它的调用生成的回复」→ 按 seq 原位回放(常规情况,与不提供 absorbedUpToSeq 时一致);
|
|
384
387
|
* - `deferred`:它之后有非空 assistant_message 是由一次没有吸收它的 model_call 生成的(它在那一步
|
|
@@ -462,8 +465,12 @@ export function buildModelRequest(input) {
|
|
|
462
465
|
const blocks = blocksOf(u.payload.content);
|
|
463
466
|
return report === undefined ? blocks : [...blocks, { type: "text", text: report }];
|
|
464
467
|
};
|
|
465
|
-
/**
|
|
468
|
+
/** 被某次模型调用跳过(运行中途到达)、尚未被吸收的可吸收事件,按 seq 升序。 */
|
|
466
469
|
let deferred = [];
|
|
470
|
+
/** An absorbable event as a request message: a user turn, or a finished task's system text. */
|
|
471
|
+
const absorbableMessage = (e) => e.type === "user_message"
|
|
472
|
+
? { role: "user", content: userBlocks(e) }
|
|
473
|
+
: { role: "system", content: renderBackgroundFinished(e.payload) };
|
|
467
474
|
/**
|
|
468
475
|
* 把已被吸收(seq ≤ upTo)的延后消息按 seq 顺序放进 messages,插在末尾连续的 system 提醒之前
|
|
469
476
|
* (若有)。这样某一步自己写在 model_call 之前的提醒(含收尾提醒)仍排在它所跟随的用户消息之后,
|
|
@@ -477,7 +484,7 @@ export function buildModelRequest(input) {
|
|
|
477
484
|
let at = messages.length;
|
|
478
485
|
while (at > 0 && messages[at - 1]?.role === "system")
|
|
479
486
|
at--;
|
|
480
|
-
messages.splice(at, 0, ...ready.map(
|
|
487
|
+
messages.splice(at, 0, ...ready.map(absorbableMessage));
|
|
481
488
|
};
|
|
482
489
|
/** (runId, callId) → 该调用的 tool_result 事件(同一调用只取第一个)。 */
|
|
483
490
|
const results = new Map();
|
|
@@ -521,21 +528,22 @@ export function buildModelRequest(input) {
|
|
|
521
528
|
for (const [i, e] of events.entries()) {
|
|
522
529
|
if (e.seq <= after)
|
|
523
530
|
continue;
|
|
531
|
+
if (isAbsorbable(e)) {
|
|
532
|
+
switch (absorbed === undefined ? "inline" : placement(i, e.seq)) {
|
|
533
|
+
case "inline":
|
|
534
|
+
// seq 更小的延后事件被同一次或更早的调用吸收:先放它们,保持发送顺序。
|
|
535
|
+
flush(e.seq - 1);
|
|
536
|
+
messages.push(absorbableMessage(e));
|
|
537
|
+
break;
|
|
538
|
+
case "deferred":
|
|
539
|
+
deferred.push(e);
|
|
540
|
+
break;
|
|
541
|
+
default:
|
|
542
|
+
break;
|
|
543
|
+
}
|
|
544
|
+
continue;
|
|
545
|
+
}
|
|
524
546
|
switch (e.type) {
|
|
525
|
-
case "user_message":
|
|
526
|
-
switch (absorbed === undefined ? "inline" : placement(i, e.seq)) {
|
|
527
|
-
case "inline":
|
|
528
|
-
// seq 更小的延后消息被同一次或更早的调用吸收:先放它们,保持用户消息的发送顺序。
|
|
529
|
-
flush(e.seq - 1);
|
|
530
|
-
messages.push({ role: "user", content: userBlocks(e) });
|
|
531
|
-
break;
|
|
532
|
-
case "deferred":
|
|
533
|
-
deferred.push(e);
|
|
534
|
-
break;
|
|
535
|
-
default:
|
|
536
|
-
break;
|
|
537
|
-
}
|
|
538
|
-
break;
|
|
539
547
|
case "model_call":
|
|
540
548
|
emitRaced(e.payload.request.toSeq);
|
|
541
549
|
if (absorbed !== undefined)
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* tools" instead). Changing it only affects snapshots written afterwards: a conversation's next
|
|
8
8
|
* run writes a new snapshot announcing the new map, and old snapshots keep their text (phase C
|
|
9
9
|
* changed the Task / Agent line, sub-agents spec §16.5; the tool-naming change shortened it to the
|
|
10
|
-
* Claude Code names, spec 2026-10-29 §6
|
|
10
|
+
* Claude Code names, spec 2026-10-29 §6; background Bash made TaskOutput and TaskStop available,
|
|
11
|
+
* spec 2026-11-05 §4.4; WebFetch and WebSearch joined the same-name list with the web tools).
|
|
11
12
|
*/
|
|
12
13
|
export declare const CLAUDE_CODE_TOOL_MAP: string;
|
|
@@ -7,17 +7,18 @@
|
|
|
7
7
|
* tools" instead). Changing it only affects snapshots written afterwards: a conversation's next
|
|
8
8
|
* run writes a new snapshot announcing the new map, and old snapshots keep their text (phase C
|
|
9
9
|
* changed the Task / Agent line, sub-agents spec §16.5; the tool-naming change shortened it to the
|
|
10
|
-
* Claude Code names, spec 2026-10-29 §6
|
|
10
|
+
* Claude Code names, spec 2026-10-29 §6; background Bash made TaskOutput and TaskStop available,
|
|
11
|
+
* spec 2026-11-05 §4.4; WebFetch and WebSearch joined the same-name list with the web tools).
|
|
11
12
|
*/
|
|
12
13
|
export const CLAUDE_CODE_TOOL_MAP = [
|
|
13
14
|
"Some skills in this conversation were written for Claude Code. Its tools Bash, Read, Write, Edit,",
|
|
14
|
-
"Glob, Grep, Skill, AskUserQuestion, ToolSearch and
|
|
15
|
+
"Glob, Grep, Skill, AskUserQuestion, ToolSearch, Agent, WebFetch and WebSearch have the same names here, when they are",
|
|
15
16
|
"in your tools. For the others:",
|
|
16
17
|
"- MultiEdit -> several Edit calls",
|
|
17
18
|
"- TodoWrite -> plugin__todo__write when it is in your tools; otherwise keep the task list in your replies",
|
|
18
19
|
"- Task -> Agent; SendMessage to a sub-agent -> Agent with resume; model names haiku / sonnet / opus -> fast / standard / capable",
|
|
19
|
-
"- TaskOutput, TaskStop ->
|
|
20
|
-
"- Any other tool a skill names (for example
|
|
20
|
+
"- TaskOutput -> TaskOutput, TaskStop -> TaskStop",
|
|
21
|
+
"- Any other tool a skill names (for example NotebookEdit, EnterWorktree) -> not available unless one of your tools does the same job",
|
|
21
22
|
// biome-ignore lint/suspicious/noTemplateCurlyInString: the literal Claude Code variable the model reads
|
|
22
23
|
"The sandbox tools exist only when this agent has a sandbox; without them a skill's scripts cannot run. A path such as ${CLAUDE_PLUGIN_ROOT}/skills/<name>/... means /skills/<name>/... after Skill has copied that skill into the sandbox.",
|
|
23
24
|
].join("\n");
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { renderBackgroundFinished } from "../../background/render.js";
|
|
1
2
|
import { latestSummary } from "./build.js";
|
|
2
3
|
/** 压缩请求的标记:放在 system 中,便于识别(model-fake 据此返回摘要)。 */
|
|
3
4
|
export const COMPACTION_MARKER = "CAPYBARA_COMPACTION";
|
|
@@ -111,6 +112,9 @@ function transcriptLine(e) {
|
|
|
111
112
|
}
|
|
112
113
|
case "reminder":
|
|
113
114
|
return `System reminder: ${e.payload.text}`;
|
|
115
|
+
// a finished background task is a system message of the request (build.ts)
|
|
116
|
+
case "background_task_finished":
|
|
117
|
+
return `System reminder: ${renderBackgroundFinished(e.payload)}`;
|
|
114
118
|
// phase D: a forked skill's report is user content of the request (build.ts)
|
|
115
119
|
case "skill_fork_result":
|
|
116
120
|
return `User: ${e.payload.text}`;
|
|
@@ -6,7 +6,8 @@ import { isForkInvocation } from "./subagents/skill-fork.js";
|
|
|
6
6
|
/**
|
|
7
7
|
* 图状态:只记录进度,消息每步从事件日志重建(runModelStep 自己读日志),checkpoint 很小。
|
|
8
8
|
* - `step`:当前(最近一次进入的)步骤编号,prepare 节点 +1;
|
|
9
|
-
* - `consumedUpToSeq
|
|
9
|
+
* - `consumedUpToSeq`:已吸收的最大可吸收事件 seq(user_message / background_task_finished; a
|
|
10
|
+
* finish TaskOutput or TaskStop already reported is absorbed like any other, rendered short);
|
|
10
11
|
* - `lastStopReason`:最近一步模型调用的停止原因;
|
|
11
12
|
* - `outcome`:图的结束方式(在决定结束的节点里写入,续跑已结束的图时直接读出,不依赖当前时间)。
|
|
12
13
|
*
|
|
@@ -148,7 +149,7 @@ export class LangGraphLoop {
|
|
|
148
149
|
let consumed = s.consumedUpToSeq;
|
|
149
150
|
// the run's first prepare (also when it runs again after a suspend on its fork's sub-agent)
|
|
150
151
|
const firstStep = s.step === 0;
|
|
151
|
-
const absorbed = await ctx.
|
|
152
|
+
const absorbed = await ctx.pendingAbsorbable(consumed);
|
|
152
153
|
for (const m of absorbed)
|
|
153
154
|
consumed = Math.max(consumed, m.seq);
|
|
154
155
|
// phase D: a run's own fork invocation is absorbed at step 1 (the run boundary,
|
package/dist/runtime/loop.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AgentDefinition } from "../agents/definition.js";
|
|
2
2
|
import type { KernelConfig } from "../config/schema.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { AbsorbableEvent } from "../conversations/events.js";
|
|
4
4
|
import type { StreamSink } from "./model-call.js";
|
|
5
5
|
/** 一次运行交给 loop 的上下文(spec 4.4)。 */
|
|
6
6
|
export interface LoopContext {
|
|
@@ -22,10 +22,11 @@ export interface LoopContext {
|
|
|
22
22
|
shutdown: AbortSignal;
|
|
23
23
|
sink: StreamSink;
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
25
|
+
* 下一个步骤间隙要吸收的事件:返回 seq > afterSeq 的可吸收事件(`user_message` 与
|
|
26
|
+
* `background_task_finished`, `isAbsorbable`;且只含本轮开始时尚未被消费的,
|
|
26
27
|
* 即 seq 也大于会话的 `consumed_seq`),按 seq 升序。loop 记录吸收到的最大 seq 作为 `consumedUpToSeq`。
|
|
27
28
|
*/
|
|
28
|
-
|
|
29
|
+
pendingAbsorbable(afterSeq: number): Promise<AbsorbableEvent[]>;
|
|
29
30
|
limits: {
|
|
30
31
|
maxSteps: number;
|
|
31
32
|
deadline: number;
|
|
@@ -5,6 +5,7 @@ import type { KernelLogger } from "../log.js";
|
|
|
5
5
|
import { DirectorySync } from "../orgs/directory-sync.js";
|
|
6
6
|
import { SandboxService } from "../sandbox/sandbox.service.js";
|
|
7
7
|
import { ToolDrift } from "../tools/drift.js";
|
|
8
|
+
import { RunQueue } from "./run-queue.js";
|
|
8
9
|
import { Waits } from "./waits.js";
|
|
9
10
|
export { MAINTENANCE_QUEUE_NAME } from "./maintenance-queue.js";
|
|
10
11
|
/** The maintenance worker's concurrency (as the hand-made worker had). */
|
|
@@ -13,7 +14,7 @@ export declare const MAINTENANCE_CONCURRENCY = 5;
|
|
|
13
14
|
* The one consumer of `cap-kernel-maintenance` (decision R11 of the Nest kernel spec): dispatches
|
|
14
15
|
* each one-off job by name to its domain (`wait-timeout` → {@link Waits}, `sandbox-destroy-for` →
|
|
15
16
|
* {@link SandboxService}, `drift-connector` → {@link ToolDrift}, `directory-sync` →
|
|
16
|
-
* {@link DirectorySync}). The name of a periodic job (a `@LockedCron` / `@LockedInterval` job,
|
|
17
|
+
* {@link DirectorySync}, `bg-wake` → {@link RunQueue.ensureRun}). The name of a periodic job (a `@LockedCron` / `@LockedInterval` job,
|
|
17
18
|
* such as `sandbox-suspend-idle`) runs that job's body once ({@link ScheduledRuns.runNow}), as the
|
|
18
19
|
* maintenance handlers did when those jobs were schedulers on this queue: an operator's or a
|
|
19
20
|
* test's one-off run, not a second schedule (decision R23 of the Nest kernel spec). Any other
|
|
@@ -24,10 +25,11 @@ export declare class MaintenanceProcessor extends WorkerHost<Worker> {
|
|
|
24
25
|
private readonly sandbox;
|
|
25
26
|
private readonly drift;
|
|
26
27
|
private readonly directory;
|
|
28
|
+
private readonly runs;
|
|
27
29
|
private readonly scheduled;
|
|
28
30
|
private readonly log;
|
|
29
31
|
private readonly queue;
|
|
30
|
-
constructor(waits: Pick<Waits, "processTimeout">, sandbox: Pick<SandboxService, "destroyFor">, drift: Pick<ToolDrift, "check">, directory: Pick<DirectorySync, "runSyncJob">, scheduled: Pick<ScheduledRuns, "runNow">, log: Pick<KernelLogger, "error" | "warn">, queue: Pick<Queue, "removeJobScheduler">);
|
|
32
|
+
constructor(waits: Pick<Waits, "processTimeout">, sandbox: Pick<SandboxService, "destroyFor">, drift: Pick<ToolDrift, "check">, directory: Pick<DirectorySync, "runSyncJob">, runs: Pick<RunQueue, "ensureRun">, scheduled: Pick<ScheduledRuns, "runNow">, log: Pick<KernelLogger, "error" | "warn">, queue: Pick<Queue, "removeJobScheduler">);
|
|
31
33
|
/**
|
|
32
34
|
* Removes the retired job schedulers (`RETIRED_SCHEDULER_IDS`, runtime/retired-schedulers.ts): every fixed-period
|
|
33
35
|
* maintenance job is a `@LockedCron` / `@LockedInterval` now. Idempotent; called once when a
|
|
@@ -9,6 +9,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
9
9
|
};
|
|
10
10
|
import { getQueueToken, OnWorkerEvent, WorkerHost } from "@nestjs/bullmq";
|
|
11
11
|
import { Inject, Injectable, Module } from "@nestjs/common";
|
|
12
|
+
import { BG_WAKE_JOB } from "../background/wake-rules.js";
|
|
12
13
|
import { configuredProcessor } from "../infra/queue/configured-processor.js";
|
|
13
14
|
import { QueueModule } from "../infra/queue/queue.module.js";
|
|
14
15
|
import { removeRetiredSchedulers } from "../infra/queue/retired-schedulers.js";
|
|
@@ -26,6 +27,7 @@ import { DRIFT_CONNECTOR_JOB } from "../tools/job-ids.js";
|
|
|
26
27
|
import { ToolsModule } from "../tools/tools.module.js";
|
|
27
28
|
import { MAINTENANCE_QUEUE_NAME } from "./maintenance-queue.js";
|
|
28
29
|
import { RETIRED_SCHEDULER_IDS } from "./retired-schedulers.js";
|
|
30
|
+
import { RunQueue } from "./run-queue.js";
|
|
29
31
|
import { RuntimeModule } from "./runtime.module.js";
|
|
30
32
|
import { WAIT_TIMEOUT_JOB, Waits } from "./waits.js";
|
|
31
33
|
export { MAINTENANCE_QUEUE_NAME } from "./maintenance-queue.js";
|
|
@@ -35,7 +37,7 @@ export const MAINTENANCE_CONCURRENCY = 5;
|
|
|
35
37
|
* The one consumer of `cap-kernel-maintenance` (decision R11 of the Nest kernel spec): dispatches
|
|
36
38
|
* each one-off job by name to its domain (`wait-timeout` → {@link Waits}, `sandbox-destroy-for` →
|
|
37
39
|
* {@link SandboxService}, `drift-connector` → {@link ToolDrift}, `directory-sync` →
|
|
38
|
-
* {@link DirectorySync}). The name of a periodic job (a `@LockedCron` / `@LockedInterval` job,
|
|
40
|
+
* {@link DirectorySync}, `bg-wake` → {@link RunQueue.ensureRun}). The name of a periodic job (a `@LockedCron` / `@LockedInterval` job,
|
|
39
41
|
* such as `sandbox-suspend-idle`) runs that job's body once ({@link ScheduledRuns.runNow}), as the
|
|
40
42
|
* maintenance handlers did when those jobs were schedulers on this queue: an operator's or a
|
|
41
43
|
* test's one-off run, not a second schedule (decision R23 of the Nest kernel spec). Any other
|
|
@@ -46,15 +48,17 @@ let MaintenanceProcessor = class MaintenanceProcessor extends WorkerHost {
|
|
|
46
48
|
sandbox;
|
|
47
49
|
drift;
|
|
48
50
|
directory;
|
|
51
|
+
runs;
|
|
49
52
|
scheduled;
|
|
50
53
|
log;
|
|
51
54
|
queue;
|
|
52
|
-
constructor(waits, sandbox, drift, directory, scheduled, log, queue) {
|
|
55
|
+
constructor(waits, sandbox, drift, directory, runs, scheduled, log, queue) {
|
|
53
56
|
super();
|
|
54
57
|
this.waits = waits;
|
|
55
58
|
this.sandbox = sandbox;
|
|
56
59
|
this.drift = drift;
|
|
57
60
|
this.directory = directory;
|
|
61
|
+
this.runs = runs;
|
|
58
62
|
this.scheduled = scheduled;
|
|
59
63
|
this.log = log;
|
|
60
64
|
this.queue = queue;
|
|
@@ -90,6 +94,13 @@ let MaintenanceProcessor = class MaintenanceProcessor extends WorkerHost {
|
|
|
90
94
|
case DIRECTORY_SYNC_JOB:
|
|
91
95
|
await this.directory.runSyncJob(job.data);
|
|
92
96
|
return;
|
|
97
|
+
// the end of a conversation's wake window (background Bash spec §3)
|
|
98
|
+
case BG_WAKE_JOB: {
|
|
99
|
+
// fired before the window ended (clock skew): it reschedules under its next retry id
|
|
100
|
+
const { conversationId, retry } = job.data;
|
|
101
|
+
await this.runs.ensureRun(conversationId, { wakeRetry: (retry ?? 0) + 1 });
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
93
104
|
default:
|
|
94
105
|
if (await this.scheduled.runNow(job.name))
|
|
95
106
|
return;
|
|
@@ -115,9 +126,10 @@ MaintenanceProcessor = __decorate([
|
|
|
115
126
|
__param(1, Inject(SandboxService)),
|
|
116
127
|
__param(2, Inject(ToolDrift)),
|
|
117
128
|
__param(3, Inject(DirectorySync)),
|
|
118
|
-
__param(4, Inject(
|
|
119
|
-
__param(5, Inject(
|
|
120
|
-
__param(6, Inject(
|
|
129
|
+
__param(4, Inject(RunQueue)),
|
|
130
|
+
__param(5, Inject(ScheduledRuns)),
|
|
131
|
+
__param(6, Inject(KERNEL_LOGGER)),
|
|
132
|
+
__param(7, Inject(getQueueToken(MAINTENANCE_QUEUE_NAME)))
|
|
121
133
|
], MaintenanceProcessor);
|
|
122
134
|
export { MaintenanceProcessor };
|
|
123
135
|
/**
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ContentBlock, type Logger, type ModelProvider, type ModelRequest, type ModelStreamEvent, type ModelUsage, type StopReason } from "@capybara-hq/plugin-sdk";
|
|
2
2
|
import type { AgentDefinition } from "../agents/definition.js";
|
|
3
|
-
import type { EventLog } from "../conversations/event-log.js";
|
|
3
|
+
import type { AppendEvent, EventLog } from "../conversations/event-log.js";
|
|
4
|
+
import { type ConversationEvent } from "../conversations/events.js";
|
|
4
5
|
import type { KernelSchemaDb } from "../db/kernel-schema.js";
|
|
5
6
|
import type { KernelConfigService } from "../infra/config/kernel-config.service.js";
|
|
6
7
|
import type { ToolRegistry, UnavailableTool } from "../tools/registry.js";
|
|
@@ -151,6 +152,21 @@ export declare function runModelStep(deps: ModelStepDeps, input: ModelStepInput)
|
|
|
151
152
|
* 其余与 `runModelStep` 相同(幂等、降级、中止)。
|
|
152
153
|
*/
|
|
153
154
|
export declare function runFinalWrapUp(deps: ModelStepDeps, input: ModelStepInput): Promise<ModelStepResult>;
|
|
155
|
+
/**
|
|
156
|
+
* Appends a model call's events (its reply or compaction outcome with its `usage`; also the usage
|
|
157
|
+
* of a `WebFetch` extraction call, `tools/builtins/web/extract.ts`). For a
|
|
158
|
+
* sub-agent's run (`input.parentRunId`) in one transaction that also adds the tokens of the usage
|
|
159
|
+
* events it newly wrote to the parent run's `subagent_tokens_used` (sub-agents spec §8.3): a usage
|
|
160
|
+
* event already in the log (an idempotent hit after a crash) adds nothing, so each call counts
|
|
161
|
+
* exactly once.
|
|
162
|
+
*/
|
|
163
|
+
export declare function appendCounted(deps: {
|
|
164
|
+
eventLog: Pick<EventLog, "append" | "notify">;
|
|
165
|
+
stepLog: Pick<StepLog, "appendCounted">;
|
|
166
|
+
}, input: {
|
|
167
|
+
conversationId: string;
|
|
168
|
+
parentRunId?: string | undefined;
|
|
169
|
+
}, events: AppendEvent[]): Promise<ConversationEvent[]>;
|
|
154
170
|
/** {@link assembleModelRequest} 的输入。 */
|
|
155
171
|
export interface AssembleModelRequestInput extends Omit<BuildModelRequestInput, "tools"> {
|
|
156
172
|
/** 本步解析出的工具;模型不支持工具(`capabilities.tools` 为 false)时不带。 */
|