@capybara-hq/kernel 0.1.0-rc.21 → 0.1.0-rc.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/admin-agents.d.ts +16 -3
- package/dist/agents/admin-agents.js +65 -7
- package/dist/agents/agents.schemas.d.ts +24 -6
- package/dist/agents/agents.service.d.ts +4 -3
- package/dist/agents/agents.service.js +39 -26
- package/dist/agents/definition.d.ts +44 -6
- package/dist/agents/definition.js +86 -18
- package/dist/agents/from-template.d.ts +6 -3
- package/dist/agents/from-template.js +57 -44
- package/dist/agents/org-templates.js +97 -41
- package/dist/agents/templates.d.ts +6 -0
- package/dist/agents/templates.js +15 -1
- package/dist/catalog/admin-catalog.controller.d.ts +2 -4
- package/dist/catalog/admin-catalog.controller.js +2 -6
- package/dist/catalog/catalog.module.js +3 -0
- package/dist/catalog/claude/report.d.ts +9 -2
- package/dist/catalog/claude/report.js +1 -0
- package/dist/catalog/claude/translate.js +1 -1
- package/dist/catalog/component-promotion.js +1 -2
- package/dist/catalog/component-state.d.ts +13 -1
- package/dist/catalog/component-state.js +14 -5
- package/dist/catalog/marketplaces.service.d.ts +1 -1
- package/dist/catalog/marketplaces.service.js +2 -1
- package/dist/catalog/org-catalog.controller.d.ts +13 -3
- package/dist/catalog/org-catalog.controller.js +26 -4
- package/dist/catalog/org-catalog.schemas.d.ts +13 -0
- package/dist/catalog/org-catalog.schemas.js +34 -0
- package/dist/catalog/org-plugin-uploads.controller.js +0 -1
- package/dist/catalog/org-plugin-uploads.d.ts +0 -1
- package/dist/catalog/org-plugin-uploads.js +0 -3
- package/dist/catalog/org-plugin-uploads.schemas.d.ts +0 -1
- package/dist/catalog/org-plugin-uploads.schemas.js +0 -2
- package/dist/catalog/platform-components.d.ts +0 -1
- package/dist/catalog/platform-components.js +3 -8
- package/dist/catalog/plugin-import.d.ts +0 -8
- package/dist/catalog/plugin-import.js +4 -35
- package/dist/catalog/plugin-install.d.ts +2 -2
- package/dist/catalog/plugin-install.js +2 -2
- package/dist/catalog/plugin-package.d.ts +7 -0
- package/dist/catalog/plugin-package.js +27 -1
- package/dist/catalog/plugin-upgrade.d.ts +5 -6
- package/dist/catalog/plugin-upgrade.js +5 -23
- package/dist/catalog/requests.service.d.ts +66 -10
- package/dist/catalog/requests.service.js +196 -15
- package/dist/channels/actions.d.ts +2 -0
- package/dist/channels/actions.js +19 -4
- package/dist/channels/cards.d.ts +16 -2
- package/dist/channels/cards.js +40 -7
- package/dist/channels/channels.module.js +3 -0
- package/dist/channels/outbound.d.ts +22 -1
- package/dist/channels/outbound.js +116 -7
- package/dist/channels/phrases.d.ts +25 -0
- package/dist/channels/phrases.js +19 -0
- package/dist/channels/threads.d.ts +12 -0
- package/dist/channels/threads.js +34 -0
- package/dist/config/schema.d.ts +23 -1
- package/dist/config/schema.js +105 -5
- package/dist/conversations/conversations.service.d.ts +42 -9
- package/dist/conversations/conversations.service.js +57 -25
- package/dist/conversations/events.d.ts +106 -11
- package/dist/conversations/events.js +121 -18
- package/dist/conversations/message-context.d.ts +6 -3
- package/dist/conversations/message-context.js +14 -10
- package/dist/conversations/queue.d.ts +15 -2
- package/dist/conversations/queue.js +22 -3
- package/dist/conversations/queue.service.d.ts +12 -6
- package/dist/conversations/queue.service.js +36 -13
- package/dist/db/kernel-schema.d.ts +105 -3
- package/dist/devices/conversation-devices.d.ts +8 -1
- package/dist/devices/conversation-devices.js +8 -0
- package/dist/devices/devices.controller.d.ts +21 -4
- package/dist/devices/devices.controller.js +46 -8
- package/dist/devices/devices.schemas.d.ts +9 -1
- package/dist/devices/devices.schemas.js +11 -3
- package/dist/devices/devices.service.d.ts +176 -4
- package/dist/devices/devices.service.js +341 -6
- package/dist/devices/dto.d.ts +56 -3
- package/dist/devices/dto.js +51 -1
- package/dist/devices/public-suffix.d.ts +6 -0
- package/dist/devices/public-suffix.js +79 -0
- package/dist/errors.d.ts +46 -5
- package/dist/errors.js +46 -5
- package/dist/evals/reconstruct.d.ts +18 -13
- package/dist/evals/reconstruct.js +50 -36
- package/dist/evals/recorded-tools.d.ts +7 -7
- package/dist/evals/recorded-tools.js +4 -3
- package/dist/evals/trajectory.d.ts +6 -1
- package/dist/evals/trajectory.js +7 -0
- package/dist/extensions/package.js +2 -2
- package/dist/http/api.module.js +5 -0
- package/dist/inbox/inbox.module.js +2 -1
- package/dist/inbox/inbox.service.d.ts +19 -4
- package/dist/inbox/inbox.service.js +14 -3
- package/dist/infra/config/kernel-config.service.js +11 -0
- package/dist/infra/events/kernel-events.d.ts +2 -1
- package/dist/local-devices/device-policy.service.d.ts +65 -0
- package/dist/local-devices/device-policy.service.js +217 -0
- package/dist/local-devices/local-device-gateway.js +4 -1
- package/dist/local-devices/local-device-provider.d.ts +40 -3
- package/dist/local-devices/local-device-provider.js +109 -7
- package/dist/local-devices/local-devices.module.d.ts +2 -1
- package/dist/local-devices/local-devices.module.js +19 -3
- package/dist/local-devices/machines.d.ts +14 -3
- package/dist/local-devices/machines.js +41 -3
- package/dist/local-devices/network-grants.d.ts +104 -0
- package/dist/local-devices/network-grants.js +288 -0
- package/dist/local-devices/policy-summary.d.ts +20 -0
- package/dist/local-devices/policy-summary.js +63 -0
- package/dist/orgs/orgs.module.js +4 -10
- package/dist/orgs/roles.d.ts +1 -1
- package/dist/orgs/roles.js +4 -0
- package/dist/orgs/settings.controller.js +2 -1
- package/dist/orgs/settings.service.d.ts +164 -12
- package/dist/orgs/settings.service.js +212 -24
- package/dist/platform/exclusions.js +11 -1
- package/dist/platform/operation.js +4 -0
- package/dist/platform/ops/admin-items.ops.js +1 -1
- package/dist/platform/ops/agent-skills.ops.js +2 -2
- package/dist/platform/ops/agent-templates.ops.js +2 -2
- package/dist/platform/ops/agents.ops.js +11 -15
- package/dist/platform/ops/devices.ops.js +3 -1
- package/dist/platform/ops/inbox.ops.js +19 -0
- package/dist/platform/ops/org-settings.ops.js +14 -5
- package/dist/platform/ops/platform.ops.d.ts +9 -1
- package/dist/platform/ops/platform.ops.js +34 -12
- package/dist/platform/ops/requests.ops.js +3 -2
- package/dist/platform/ops/schedules.ops.d.ts +21 -0
- package/dist/platform/ops/schedules.ops.js +470 -0
- package/dist/platform/ops/skills.ops.js +3 -3
- package/dist/platform/platform-ops.module.d.ts +2 -1
- package/dist/platform/platform-ops.module.js +5 -0
- package/dist/platform/route-schemas.js +3 -0
- package/dist/roles/worker.module.js +3 -0
- package/dist/runtime/context/build.js +13 -4
- package/dist/runtime/context/compaction.js +6 -3
- package/dist/runtime/context/device-paths.d.ts +43 -21
- package/dist/runtime/context/device-paths.js +104 -21
- package/dist/runtime/context/run-context.d.ts +9 -0
- package/dist/runtime/context/run-context.js +8 -0
- package/dist/runtime/context/skills.d.ts +14 -1
- package/dist/runtime/context/skills.js +36 -5
- package/dist/runtime/maintenance.d.ts +4 -2
- package/dist/runtime/maintenance.js +16 -5
- package/dist/runtime/run-finish.d.ts +6 -1
- package/dist/runtime/run-finish.js +16 -2
- package/dist/runtime/run-queue.js +21 -2
- package/dist/runtime/run-worker.js +14 -33
- package/dist/runtime/runtime.module.js +3 -0
- package/dist/runtime/subagents/definition.d.ts +32 -14
- package/dist/runtime/subagents/definition.js +106 -109
- package/dist/runtime/subagents/dispatch.js +4 -3
- package/dist/runtime/subagents/preamble.d.ts +2 -1
- package/dist/runtime/subagents/preamble.js +2 -1
- package/dist/runtime/waits.js +14 -4
- package/dist/sandbox/sandbox.service.d.ts +120 -10
- package/dist/sandbox/sandbox.service.js +335 -28
- package/dist/sandbox/tiers.d.ts +86 -0
- package/dist/sandbox/tiers.js +96 -0
- package/dist/schedules/effective-settings.d.ts +16 -0
- package/dist/schedules/effective-settings.js +17 -0
- package/dist/schedules/errors.d.ts +8 -0
- package/dist/schedules/errors.js +8 -0
- package/dist/schedules/fire.d.ts +118 -0
- package/dist/schedules/fire.js +625 -0
- package/dist/schedules/grant-rules.d.ts +94 -0
- package/dist/schedules/grant-rules.js +126 -0
- package/dist/schedules/job-ids.d.ts +32 -0
- package/dist/schedules/job-ids.js +27 -0
- package/dist/schedules/pause.d.ts +9 -0
- package/dist/schedules/pause.js +33 -0
- package/dist/schedules/run-tracker.d.ts +81 -0
- package/dist/schedules/run-tracker.js +333 -0
- package/dist/schedules/scan.job.d.ts +64 -0
- package/dist/schedules/scan.job.js +303 -0
- package/dist/schedules/schedule-math.d.ts +31 -0
- package/dist/schedules/schedule-math.js +223 -0
- package/dist/schedules/scheduled-tasks.service.d.ts +351 -0
- package/dist/schedules/scheduled-tasks.service.js +1193 -0
- package/dist/schedules/schedules.controller.d.ts +68 -0
- package/dist/schedules/schedules.controller.js +242 -0
- package/dist/schedules/schedules.module.d.ts +16 -0
- package/dist/schedules/schedules.module.js +65 -0
- package/dist/schedules/schedules.schemas.d.ts +316 -0
- package/dist/schedules/schedules.schemas.js +186 -0
- package/dist/schedules/store.d.ts +81 -0
- package/dist/schedules/store.js +390 -0
- package/dist/schedules/store.module.d.ts +6 -0
- package/dist/schedules/store.module.js +21 -0
- package/dist/schedules/types.d.ts +108 -0
- package/dist/schedules/types.js +1 -0
- package/dist/schedules/unattended.d.ts +117 -0
- package/dist/schedules/unattended.js +228 -0
- package/dist/setup/oauth-token-probe.js +8 -4
- package/dist/skills/agent-skills.service.d.ts +4 -8
- package/dist/skills/agent-skills.service.js +18 -53
- package/dist/skills/catalog.d.ts +65 -62
- package/dist/skills/catalog.js +109 -206
- package/dist/skills/conversation-catalog.d.ts +3 -3
- package/dist/skills/conversation-catalog.js +5 -12
- package/dist/skills/invoke.d.ts +2 -2
- package/dist/skills/skills.controller.d.ts +3 -1
- package/dist/skills/skills.service.d.ts +38 -37
- package/dist/skills/skills.service.js +168 -107
- package/dist/skills/usable.d.ts +57 -8
- package/dist/skills/usable.js +172 -38
- package/dist/tools/approvals.controller.d.ts +4 -2
- package/dist/tools/approvals.controller.js +17 -2
- package/dist/tools/approvals.schemas.d.ts +1 -0
- package/dist/tools/approvals.schemas.js +3 -1
- package/dist/tools/approvals.service.d.ts +182 -7
- package/dist/tools/approvals.service.js +597 -13
- package/dist/tools/builtin-names.d.ts +25 -4
- package/dist/tools/builtin-names.js +45 -4
- package/dist/tools/builtins/builtin-tools.d.ts +8 -0
- package/dist/tools/builtins/builtin-tools.js +23 -2
- package/dist/tools/builtins/sandbox/bash.js +16 -7
- package/dist/tools/builtins/sandbox/common.d.ts +1 -1
- package/dist/tools/builtins/sandbox/common.js +33 -10
- package/dist/tools/builtins/sandbox/edit.js +7 -3
- package/dist/tools/builtins/sandbox/file-state.d.ts +31 -1
- package/dist/tools/builtins/sandbox/file-state.js +33 -3
- package/dist/tools/builtins/sandbox/write.js +8 -4
- package/dist/tools/builtins/schedules.d.ts +107 -0
- package/dist/tools/builtins/schedules.js +789 -0
- package/dist/tools/elicitation.d.ts +2 -0
- package/dist/tools/elicitation.js +1 -1
- package/dist/tools/fixed-ask.d.ts +7 -0
- package/dist/tools/fixed-ask.js +9 -0
- package/dist/tools/network-asks.d.ts +109 -0
- package/dist/tools/network-asks.js +221 -0
- package/dist/tools/pipeline.d.ts +53 -6
- package/dist/tools/pipeline.js +202 -13
- package/dist/tools/policy.d.ts +21 -8
- package/dist/tools/policy.js +63 -9
- package/dist/tools/registry.d.ts +10 -1
- package/dist/tools/tools.module.js +12 -0
- package/package.json +2 -2
- package/src/migrations/0113_scheduled_tasks.sql +108 -0
- package/src/migrations/0114_network_asks.sql +23 -0
- package/src/migrations/0115_network_requests.sql +28 -0
- package/src/migrations/0116_skills_default_on.sql +37 -0
- package/src/migrations/0117_sandbox_tiers.sql +11 -0
package/dist/config/schema.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isIP } from "node:net";
|
|
2
|
-
import { DOCUMENT_MEDIA_TYPES, IMAGE_MEDIA_TYPES, validateAllowHost, } from "@capybara-hq/plugin-sdk";
|
|
2
|
+
import { DEV_HOSTS, DOCUMENT_MEDIA_TYPES, IMAGE_MEDIA_TYPES, tierAtMost, validateAllowHost, } from "@capybara-hq/plugin-sdk";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { LOG_FORMATS, LOG_LEVELS } from "../log.js";
|
|
5
5
|
import { noProxyEntryProblem, proxyUrlProblem } from "../net/proxy.js";
|
|
@@ -965,10 +965,24 @@ export const KernelConfigSchema = z.object({
|
|
|
965
965
|
.int()
|
|
966
966
|
.min(0)
|
|
967
967
|
.refine((n) => n === 0 || n >= 10_000, "0 (no limit) or at least 10,000")
|
|
968
|
-
.default(
|
|
968
|
+
.default(0)
|
|
969
969
|
.meta(meta({
|
|
970
970
|
hot: true,
|
|
971
|
-
description: "Tokens (input, output and cache) all sub-agents of the tree under a person's message may use together; at the cap running sub-agents stop and new dispatches are refused. 0 means no limit; otherwise at least 10,000. Organizations can be given their own value in subagentLimitOverrides",
|
|
971
|
+
description: "Tokens (input, output and cache) all sub-agents of the tree under a person's message may use together; at the cap running sub-agents stop and new dispatches are refused. 0 (the default) means no limit; otherwise at least 10,000. Organizations can be given their own value in subagentLimitOverrides",
|
|
972
|
+
})),
|
|
973
|
+
})
|
|
974
|
+
.prefault({}),
|
|
975
|
+
skills: z
|
|
976
|
+
.object({
|
|
977
|
+
catalogBudgetChars: z
|
|
978
|
+
.number()
|
|
979
|
+
.int()
|
|
980
|
+
.min(1_000)
|
|
981
|
+
.max(1_000_000)
|
|
982
|
+
.default(16_000)
|
|
983
|
+
.meta(meta({
|
|
984
|
+
hot: true,
|
|
985
|
+
description: "Characters the skills catalog lines with descriptions may take in a conversation's skills snapshot (about 4 characters per token). At run start the skills are ranked (the agent's own and the ones it shared, builtin, the organization's own, then plugin skills; by name within each) and keep their descriptions while the running total fits; the rest are listed by name only. Recorded in the snapshot, so a change applies from the next snapshot a run start writes",
|
|
972
986
|
})),
|
|
973
987
|
})
|
|
974
988
|
.prefault({}),
|
|
@@ -1030,6 +1044,46 @@ export const KernelConfigSchema = z.object({
|
|
|
1030
1044
|
.prefault({}),
|
|
1031
1045
|
})
|
|
1032
1046
|
.prefault({}),
|
|
1047
|
+
schedules: z
|
|
1048
|
+
.object({
|
|
1049
|
+
minIntervalFloorMinutes: z
|
|
1050
|
+
.number()
|
|
1051
|
+
.int()
|
|
1052
|
+
.positive()
|
|
1053
|
+
.default(5)
|
|
1054
|
+
.meta(meta({
|
|
1055
|
+
hot: true,
|
|
1056
|
+
description: "Smallest value an organization may set for the minimum gap between two fire times of a scheduled task, in minutes; a lower org value is clamped up to it",
|
|
1057
|
+
})),
|
|
1058
|
+
maxTasksPerMemberCap: z
|
|
1059
|
+
.number()
|
|
1060
|
+
.int()
|
|
1061
|
+
.positive()
|
|
1062
|
+
.default(100)
|
|
1063
|
+
.meta(meta({
|
|
1064
|
+
hot: true,
|
|
1065
|
+
description: "Largest number of scheduled tasks per member an organization may allow; a higher org value is clamped down to it",
|
|
1066
|
+
})),
|
|
1067
|
+
maxTasksPerOrgCap: z
|
|
1068
|
+
.number()
|
|
1069
|
+
.int()
|
|
1070
|
+
.positive()
|
|
1071
|
+
.default(2000)
|
|
1072
|
+
.meta(meta({
|
|
1073
|
+
hot: true,
|
|
1074
|
+
description: "Largest number of scheduled tasks per organization an organization may allow; a higher org value is clamped down to it",
|
|
1075
|
+
})),
|
|
1076
|
+
maxRunsPerHourCap: z
|
|
1077
|
+
.number()
|
|
1078
|
+
.int()
|
|
1079
|
+
.positive()
|
|
1080
|
+
.default(600)
|
|
1081
|
+
.meta(meta({
|
|
1082
|
+
hot: true,
|
|
1083
|
+
description: "Largest number of scheduled task runs per organization per hour an organization may allow; a higher org value is clamped down to it",
|
|
1084
|
+
})),
|
|
1085
|
+
})
|
|
1086
|
+
.prefault({}),
|
|
1033
1087
|
sandbox: z
|
|
1034
1088
|
.object({
|
|
1035
1089
|
image: z
|
|
@@ -1151,10 +1205,14 @@ export const KernelConfigSchema = z.object({
|
|
|
1151
1205
|
description: "Minutes a device's instance may run continuously before it is suspended even while in use (skipped while a command is running)",
|
|
1152
1206
|
})),
|
|
1153
1207
|
egress: z
|
|
1154
|
-
.enum(["none", "allowlist",
|
|
1208
|
+
.enum(["none", "allowlist"], {
|
|
1209
|
+
error: (iss) => iss.input === "open"
|
|
1210
|
+
? 'sandbox.limits.egress no longer takes "open": open egress is the open sandbox tier now; set sandbox.tiers.max to "open" (and egress to "allowlist")'
|
|
1211
|
+
: undefined,
|
|
1212
|
+
})
|
|
1155
1213
|
.default("allowlist")
|
|
1156
1214
|
.meta(meta({
|
|
1157
|
-
description:
|
|
1215
|
+
description: 'Outbound network of sandboxed devices: none (no tier reaches the network, the kill switch) or allowlist (strict reaches allowHosts, dev adds devHosts, open reaches any public host). Open egress is the open tier: set sandbox.tiers.max to "open"',
|
|
1158
1216
|
})),
|
|
1159
1217
|
allowHosts: z
|
|
1160
1218
|
.array(z.string())
|
|
@@ -1169,6 +1227,48 @@ export const KernelConfigSchema = z.object({
|
|
|
1169
1227
|
.meta(meta({
|
|
1170
1228
|
description: "Hosts cloud device instances may reach when egress is allowlist: lowercase hostnames, optional leading '*.', no IPs, ports or internal-only names; applies to instances created after the change",
|
|
1171
1229
|
})),
|
|
1230
|
+
devHosts: z
|
|
1231
|
+
.array(z.string())
|
|
1232
|
+
.default([...DEV_HOSTS])
|
|
1233
|
+
.superRefine((hosts, ctx) => {
|
|
1234
|
+
hosts.forEach((h, i) => {
|
|
1235
|
+
for (const message of validateAllowHost(h)) {
|
|
1236
|
+
ctx.addIssue({ code: "custom", path: [i], message: `${h}: ${message}` });
|
|
1237
|
+
}
|
|
1238
|
+
});
|
|
1239
|
+
})
|
|
1240
|
+
.meta(meta({
|
|
1241
|
+
description: "Hosts the dev sandbox tier adds to the allowlist (package registries, source hosts, tool downloads) when egress is allowlist; same format as allowHosts",
|
|
1242
|
+
})),
|
|
1243
|
+
})
|
|
1244
|
+
.prefault({}),
|
|
1245
|
+
tiers: z
|
|
1246
|
+
.object({
|
|
1247
|
+
max: z
|
|
1248
|
+
.enum(["strict", "dev", "open"])
|
|
1249
|
+
.default("dev")
|
|
1250
|
+
.meta(meta({
|
|
1251
|
+
hot: true,
|
|
1252
|
+
description: "Highest sandbox tier any organization may reach: strict (the allowlist only), dev (adds devHosts and local development affordances) or open (any public host); organizations and devices choose at most this",
|
|
1253
|
+
})),
|
|
1254
|
+
default: z
|
|
1255
|
+
.enum(["strict", "dev", "open"])
|
|
1256
|
+
.default("dev")
|
|
1257
|
+
.meta(meta({
|
|
1258
|
+
hot: true,
|
|
1259
|
+
description: "Sandbox tier of a device whose owner chose none, unless its organization sets its own default; at most sandbox.tiers.max",
|
|
1260
|
+
})),
|
|
1261
|
+
allowUnsandboxed: z
|
|
1262
|
+
.boolean()
|
|
1263
|
+
.default(true)
|
|
1264
|
+
.meta(meta({
|
|
1265
|
+
hot: true,
|
|
1266
|
+
description: "Whether a local device may run commands without a sandbox (its owner's local choice); it only applies where the organization's ceiling is open, and an organization may forbid it",
|
|
1267
|
+
})),
|
|
1268
|
+
})
|
|
1269
|
+
.refine((t) => tierAtMost(t.default, t.max), {
|
|
1270
|
+
message: "sandbox.tiers.default must not be above sandbox.tiers.max",
|
|
1271
|
+
path: ["default"],
|
|
1172
1272
|
})
|
|
1173
1273
|
.prefault({}),
|
|
1174
1274
|
})
|
|
@@ -9,7 +9,9 @@ import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
|
9
9
|
import { KernelEvents } from "../infra/events/kernel-events.js";
|
|
10
10
|
import type { KernelLogger } from "../log.js";
|
|
11
11
|
import { ProviderRegistry } from "../runtime/providers.js";
|
|
12
|
+
import type { ScheduleMarker } from "../schedules/types.js";
|
|
12
13
|
import { type RenderedInvocation, SkillInvoker } from "../skills/invoke.js";
|
|
14
|
+
import { type ApprovalRecord, ApprovalsService } from "../tools/approvals.service.js";
|
|
13
15
|
import { ConnectorContent } from "../tools/connector-content.js";
|
|
14
16
|
import { type QuestionRecord, QuestionsService } from "../tools/questions.service.js";
|
|
15
17
|
import { ConversationAccess } from "./access.js";
|
|
@@ -46,6 +48,8 @@ export interface ConversationView {
|
|
|
46
48
|
* sub-agent's is null: it works in its root conversation's.
|
|
47
49
|
*/
|
|
48
50
|
deviceId: string | null;
|
|
51
|
+
/** The scheduled task that created it (a `new`-mode task's run); null otherwise (spec §4). */
|
|
52
|
+
scheduledTaskId: string | null;
|
|
49
53
|
/**
|
|
50
54
|
* What the latest run is doing: `running` (queued or running), `waiting` (an approval or a
|
|
51
55
|
* question), else null. Only the list queries compute it; other responses carry null.
|
|
@@ -101,6 +105,17 @@ export interface SubagentView {
|
|
|
101
105
|
pendingApprovalIds: string[];
|
|
102
106
|
pendingQuestionIds: string[];
|
|
103
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* What a message skipped (reply-while-question spec §8.1, network ask-to-allow spec §6.7): its
|
|
110
|
+
* author's pending questions and network asks, and the highest seq the network skips wrote per
|
|
111
|
+
* conversation (a sub-agent's ask is in its own conversation).
|
|
112
|
+
*/
|
|
113
|
+
export interface ReplySkips {
|
|
114
|
+
questions: QuestionRecord[];
|
|
115
|
+
network: ApprovalRecord[];
|
|
116
|
+
seqs: ReadonlyMap<string, number>;
|
|
117
|
+
}
|
|
118
|
+
export declare const NO_REPLY_SKIPS: ReplySkips;
|
|
104
119
|
/** 会话服务用到的运行控制:投递运行(RunQueue)与跨副本中止(RunAbort)。 */
|
|
105
120
|
export interface RunControl {
|
|
106
121
|
/** 有未消费的消息且没有进行中的运行时投递一轮运行;返回 runId 或 null。 */
|
|
@@ -185,6 +200,15 @@ export interface UserMessageInput {
|
|
|
185
200
|
*/
|
|
186
201
|
im?: ImSenderContext;
|
|
187
202
|
}
|
|
203
|
+
/**
|
|
204
|
+
* Message options only kernel callers pass (a scheduled task's fire, scheduled tasks spec §6), never
|
|
205
|
+
* an HTTP body: the schedule marker the `user_message` carries and a zone that beats every other
|
|
206
|
+
* source of the message's `timeZone` (`readMessageContext`).
|
|
207
|
+
*/
|
|
208
|
+
export interface InternalMessageOptions {
|
|
209
|
+
schedule?: ScheduleMarker;
|
|
210
|
+
timeZoneOverride?: string;
|
|
211
|
+
}
|
|
188
212
|
/**
|
|
189
213
|
* 会话:只有所有者可见;每次访问都实时复核 agent 对所有者仍可用(spec 3.6 R5),
|
|
190
214
|
* 不可用时会话也按不存在处理(`conversation.not_found`)。
|
|
@@ -211,6 +235,8 @@ export declare class ConversationsService {
|
|
|
211
235
|
private readonly devices;
|
|
212
236
|
/** A starter's message skips the run's pending questions (reply-while-question spec §8.1). */
|
|
213
237
|
private readonly questions;
|
|
238
|
+
/** ... and its pending network asks (network ask-to-allow spec §6.7). */
|
|
239
|
+
private readonly approvals;
|
|
214
240
|
private readonly events;
|
|
215
241
|
readonly txHost: TransactionHost;
|
|
216
242
|
constructor(db: KernelDb, eventLog: EventLog, agents: Pick<AgentLookup, "get">, access: Pick<ConversationAccess, "isAccessible">,
|
|
@@ -229,7 +255,9 @@ export declare class ConversationsService {
|
|
|
229
255
|
/** The device a new conversation is bound to (environments spec §4.1 item 1). */
|
|
230
256
|
devices: Pick<ConversationDevices, "forNew">,
|
|
231
257
|
/** A starter's message skips the run's pending questions (reply-while-question spec §8.1). */
|
|
232
|
-
questions: Pick<QuestionsService, "skipPendingIn">,
|
|
258
|
+
questions: Pick<QuestionsService, "skipPendingIn">,
|
|
259
|
+
/** ... and its pending network asks (network ask-to-allow spec §6.7). */
|
|
260
|
+
approvals: Pick<ApprovalsService, "skipNetworkIn">, events: Pick<KernelEvents, "emit">, txHost: TransactionHost);
|
|
233
261
|
/**
|
|
234
262
|
* 不阻塞地调用一次 `ensureRun`(打开 SSE、读事件时):它幂等,并顺带清理孤儿运行,
|
|
235
263
|
* 会话不会因为某次运行结束后的投递失败而永远停在「运行中」。失败只记日志。
|
|
@@ -250,10 +278,12 @@ export declare class ConversationsService {
|
|
|
250
278
|
* `agent.not_found` and nothing is written. Queues a run afterwards, like `postUserMessage`.
|
|
251
279
|
* `events` are every event the create wrote, in seq order from seq 1 (a `model_switched` before
|
|
252
280
|
* the message when the send switched), so a client can seed the new conversation's log whole.
|
|
281
|
+
* `internal` (kernel callers only): a scheduled task's marker, which also sets
|
|
282
|
+
* `conversations.scheduled_task_id`, and its zone override.
|
|
253
283
|
*/
|
|
254
284
|
createWithMessage(orgId: string, accountId: string, agentId: string, input: UserMessageInput & {
|
|
255
285
|
clientMessageId: string;
|
|
256
|
-
}, pick?: NewConversationDevice): Promise<{
|
|
286
|
+
}, pick?: NewConversationDevice, internal?: InternalMessageOptions): Promise<{
|
|
257
287
|
conversation: ConversationView;
|
|
258
288
|
event: ConversationEvent;
|
|
259
289
|
events: ConversationEvent[];
|
|
@@ -418,18 +448,21 @@ export declare class ConversationsService {
|
|
|
418
448
|
/**
|
|
419
449
|
* Skips, in the caller's transaction (it wrote `accountId`'s message at `messageSeq` and holds the
|
|
420
450
|
* conversation row lock), the pending questions that message closes (reply-while-question spec
|
|
421
|
-
* §8.1)
|
|
422
|
-
*
|
|
451
|
+
* §8.1) and the pending network asks of the author's runs, here and in the sub-agents'
|
|
452
|
+
* conversations (network ask-to-allow spec §6.7). The queue's "send now" uses it as the direct
|
|
453
|
+
* send does; announce after the commit with {@link announceSkipped}. `toSeq` is the highest seq
|
|
454
|
+
* written in this conversation (null: none).
|
|
423
455
|
*/
|
|
424
|
-
|
|
425
|
-
|
|
456
|
+
skipWaitsIn(conversationId: string, accountId: string, messageSeq: number): Promise<{
|
|
457
|
+
skipped: ReplySkips;
|
|
426
458
|
toSeq: number | null;
|
|
427
459
|
}>;
|
|
428
460
|
/**
|
|
429
|
-
* After the commit: announces each skipped question (`question.answered`, outcome `skipped`)
|
|
430
|
-
*
|
|
461
|
+
* After the commit: announces each skipped question (`question.answered`, outcome `skipped`) and
|
|
462
|
+
* network ask (`approval.decided`, status `skipped`; a sub-agent's conversation is notified
|
|
463
|
+
* first), so its run resumes (waits) and its IM card updates (channel jobs).
|
|
431
464
|
*/
|
|
432
|
-
announceSkipped(
|
|
465
|
+
announceSkipped(skipped: ReplySkips): Promise<void>;
|
|
433
466
|
/**
|
|
434
467
|
* Writes the message (preceded by its `model_switched` when it switches) inside `t` and updates
|
|
435
468
|
* `conversations.selection`; returns the events written, in seq order (the `user_message`
|
|
@@ -24,6 +24,7 @@ import { ProviderRegistry } from "../runtime/providers.js";
|
|
|
24
24
|
import { RunControl as RunControlService } from "../runtime/run-control.js";
|
|
25
25
|
import { rootConversationOf } from "../runtime/subagents/child.js";
|
|
26
26
|
import { SkillInvoker } from "../skills/invoke.js";
|
|
27
|
+
import { ApprovalsService } from "../tools/approvals.service.js";
|
|
27
28
|
import { ConnectorContent } from "../tools/connector-content.js";
|
|
28
29
|
import { QuestionsService } from "../tools/questions.service.js";
|
|
29
30
|
import { ConversationAccess, parentReachable } from "./access.js";
|
|
@@ -56,6 +57,7 @@ function activitySql(ref) {
|
|
|
56
57
|
)`;
|
|
57
58
|
}
|
|
58
59
|
const notFound = () => new ApiError("conversation.not_found", "Conversation not found");
|
|
60
|
+
export const NO_REPLY_SKIPS = { questions: [], network: [], seqs: new Map() };
|
|
59
61
|
export { userMessageIdemKey } from "./idem-keys.js";
|
|
60
62
|
const COLUMNS = [
|
|
61
63
|
"id",
|
|
@@ -72,6 +74,7 @@ const COLUMNS = [
|
|
|
72
74
|
"subagent_type",
|
|
73
75
|
"archived_at",
|
|
74
76
|
"device_id",
|
|
77
|
+
"scheduled_task_id",
|
|
75
78
|
];
|
|
76
79
|
function toView(r) {
|
|
77
80
|
return {
|
|
@@ -89,6 +92,7 @@ function toView(r) {
|
|
|
89
92
|
subagentType: r.subagent_type,
|
|
90
93
|
archivedAt: r.archived_at,
|
|
91
94
|
deviceId: r.device_id,
|
|
95
|
+
scheduledTaskId: r.scheduled_task_id,
|
|
92
96
|
activity: r.activity ?? null,
|
|
93
97
|
};
|
|
94
98
|
}
|
|
@@ -133,6 +137,7 @@ let ConversationsService = class ConversationsService {
|
|
|
133
137
|
background;
|
|
134
138
|
devices;
|
|
135
139
|
questions;
|
|
140
|
+
approvals;
|
|
136
141
|
events;
|
|
137
142
|
txHost;
|
|
138
143
|
constructor(db, eventLog, agents, access,
|
|
@@ -151,7 +156,9 @@ let ConversationsService = class ConversationsService {
|
|
|
151
156
|
/** The device a new conversation is bound to (environments spec §4.1 item 1). */
|
|
152
157
|
devices,
|
|
153
158
|
/** A starter's message skips the run's pending questions (reply-while-question spec §8.1). */
|
|
154
|
-
questions,
|
|
159
|
+
questions,
|
|
160
|
+
/** ... and its pending network asks (network ask-to-allow spec §6.7). */
|
|
161
|
+
approvals, events, txHost) {
|
|
155
162
|
this.db = db;
|
|
156
163
|
this.eventLog = eventLog;
|
|
157
164
|
this.agents = agents;
|
|
@@ -165,6 +172,7 @@ let ConversationsService = class ConversationsService {
|
|
|
165
172
|
this.background = background;
|
|
166
173
|
this.devices = devices;
|
|
167
174
|
this.questions = questions;
|
|
175
|
+
this.approvals = approvals;
|
|
168
176
|
this.events = events;
|
|
169
177
|
this.txHost = txHost;
|
|
170
178
|
}
|
|
@@ -207,8 +215,10 @@ let ConversationsService = class ConversationsService {
|
|
|
207
215
|
* `agent.not_found` and nothing is written. Queues a run afterwards, like `postUserMessage`.
|
|
208
216
|
* `events` are every event the create wrote, in seq order from seq 1 (a `model_switched` before
|
|
209
217
|
* the message when the send switched), so a client can seed the new conversation's log whole.
|
|
218
|
+
* `internal` (kernel callers only): a scheduled task's marker, which also sets
|
|
219
|
+
* `conversations.scheduled_task_id`, and its zone override.
|
|
210
220
|
*/
|
|
211
|
-
async createWithMessage(orgId, accountId, agentId, input, pick = {}) {
|
|
221
|
+
async createWithMessage(orgId, accountId, agentId, input, pick = {}, internal = {}) {
|
|
212
222
|
const agent = await this.agents.get(orgId, agentId, accountId);
|
|
213
223
|
const prior = await this.findCreated(orgId, accountId, agentId, input.clientMessageId);
|
|
214
224
|
if (prior)
|
|
@@ -218,7 +228,7 @@ let ConversationsService = class ConversationsService {
|
|
|
218
228
|
const extra = await this.resolveExtra(orgId, accountId, input);
|
|
219
229
|
const invoked = await this.prepareSkill(orgId, agentId, undefined, agent.definition, input);
|
|
220
230
|
const id = randomUUID();
|
|
221
|
-
const all = await this.createIn({ id, orgId, accountId, agentId, deviceId }, input, next, extra, invoked);
|
|
231
|
+
const all = await this.createIn({ id, orgId, accountId, agentId, deviceId }, input, next, extra, invoked, internal);
|
|
222
232
|
const written = all?.at(-1);
|
|
223
233
|
if (!all || !written) {
|
|
224
234
|
const raced = await this.findCreated(orgId, accountId, agentId, input.clientMessageId);
|
|
@@ -232,7 +242,7 @@ let ConversationsService = class ConversationsService {
|
|
|
232
242
|
}
|
|
233
243
|
/** The conversation row and its first message (undefined: a concurrent retry committed first). */
|
|
234
244
|
// its own transaction: the caller notifies and publishes after the commit
|
|
235
|
-
async createIn(conv, input, next, extra, invoked) {
|
|
245
|
+
async createIn(conv, input, next, extra, invoked, internal) {
|
|
236
246
|
const { id, orgId, accountId } = conv;
|
|
237
247
|
const row = await this.db
|
|
238
248
|
.insertInto("conversations")
|
|
@@ -243,6 +253,7 @@ let ConversationsService = class ConversationsService {
|
|
|
243
253
|
account_id: accountId,
|
|
244
254
|
device_id: conv.deviceId,
|
|
245
255
|
create_request_id: input.clientMessageId,
|
|
256
|
+
scheduled_task_id: internal.schedule?.taskId ?? null,
|
|
246
257
|
})
|
|
247
258
|
.onConflict((oc) => oc
|
|
248
259
|
.columns(["org_id", "account_id", "create_request_id"])
|
|
@@ -255,8 +266,7 @@ let ConversationsService = class ConversationsService {
|
|
|
255
266
|
return undefined;
|
|
256
267
|
const blocks = await this.bindIn(orgId, id, accountId, input.files ?? []);
|
|
257
268
|
// a new conversation has no run yet, so nothing to skip
|
|
258
|
-
return (await this.writeMessage(orgId, id, accountId, input, next, extra, blocks, invoked))
|
|
259
|
-
.events;
|
|
269
|
+
return (await this.writeMessage(orgId, id, accountId, input, next, extra, blocks, invoked, internal)).events;
|
|
260
270
|
}
|
|
261
271
|
/**
|
|
262
272
|
* The conversation (and its first event) an earlier first send with this id created. The id used
|
|
@@ -494,14 +504,14 @@ let ConversationsService = class ConversationsService {
|
|
|
494
504
|
SELECT page.agent_id, page.latest_at, v.definition ->> 'name' AS agent_name,
|
|
495
505
|
a.profile_avatar, a.profile_updated_at, cs.id, cs.org_id, cs.account_id, cs.title, cs.title_source, cs.selection, cs.last_seq,
|
|
496
506
|
cs.created_at, cs.updated_at, cs.parent_conversation_id, cs.subagent_type,
|
|
497
|
-
cs.archived_at, cs.device_id, cs.activity
|
|
507
|
+
cs.archived_at, cs.device_id, cs.scheduled_task_id, cs.activity
|
|
498
508
|
FROM page
|
|
499
509
|
JOIN capybara.agents a ON a.id = page.agent_id
|
|
500
510
|
JOIN capybara.agent_versions v ON v.agent_id = a.id AND v.version = a.current_version
|
|
501
511
|
CROSS JOIN LATERAL (
|
|
502
512
|
SELECT c.id, c.org_id, c.account_id, c.title, c.title_source, c.selection, c.last_seq,
|
|
503
513
|
c.created_at, c.updated_at, c.parent_conversation_id, c.subagent_type,
|
|
504
|
-
c.archived_at, c.device_id, ${activitySql("c")} AS activity
|
|
514
|
+
c.archived_at, c.device_id, c.scheduled_task_id, ${activitySql("c")} AS activity
|
|
505
515
|
FROM capybara.conversations c
|
|
506
516
|
WHERE c.org_id = ${orgId} AND c.account_id = ${accountId} AND c.kind = 'chat'
|
|
507
517
|
AND c.deleted_at IS NULL AND ${archivedFilter} ${searchFilter} ${stateFilter}
|
|
@@ -798,18 +808,25 @@ let ConversationsService = class ConversationsService {
|
|
|
798
808
|
/**
|
|
799
809
|
* Skips, in the caller's transaction (it wrote `accountId`'s message at `messageSeq` and holds the
|
|
800
810
|
* conversation row lock), the pending questions that message closes (reply-while-question spec
|
|
801
|
-
* §8.1)
|
|
802
|
-
*
|
|
811
|
+
* §8.1) and the pending network asks of the author's runs, here and in the sub-agents'
|
|
812
|
+
* conversations (network ask-to-allow spec §6.7). The queue's "send now" uses it as the direct
|
|
813
|
+
* send does; announce after the commit with {@link announceSkipped}. `toSeq` is the highest seq
|
|
814
|
+
* written in this conversation (null: none).
|
|
803
815
|
*/
|
|
804
|
-
async
|
|
805
|
-
|
|
816
|
+
async skipWaitsIn(conversationId, accountId, messageSeq) {
|
|
817
|
+
const q = await this.questions.skipPendingIn(conversationId, accountId, messageSeq);
|
|
818
|
+
const n = await this.approvals.skipNetworkIn(conversationId, accountId);
|
|
819
|
+
const here = n.seqs.get(conversationId);
|
|
820
|
+
const toSeq = q.toSeq === null && here === undefined ? null : Math.max(q.toSeq ?? 0, here ?? 0);
|
|
821
|
+
return { skipped: { questions: q.records, network: n.records, seqs: n.seqs }, toSeq };
|
|
806
822
|
}
|
|
807
823
|
/**
|
|
808
|
-
* After the commit: announces each skipped question (`question.answered`, outcome `skipped`)
|
|
809
|
-
*
|
|
824
|
+
* After the commit: announces each skipped question (`question.answered`, outcome `skipped`) and
|
|
825
|
+
* network ask (`approval.decided`, status `skipped`; a sub-agent's conversation is notified
|
|
826
|
+
* first), so its run resumes (waits) and its IM card updates (channel jobs).
|
|
810
827
|
*/
|
|
811
|
-
async announceSkipped(
|
|
812
|
-
for (const q of
|
|
828
|
+
async announceSkipped(skipped) {
|
|
829
|
+
for (const q of skipped.questions) {
|
|
813
830
|
await this.events.emit("question.answered", {
|
|
814
831
|
id: q.id,
|
|
815
832
|
orgId: q.orgId,
|
|
@@ -818,6 +835,18 @@ let ConversationsService = class ConversationsService {
|
|
|
818
835
|
outcome: "skipped",
|
|
819
836
|
});
|
|
820
837
|
}
|
|
838
|
+
for (const [conversationId, seq] of skipped.seqs) {
|
|
839
|
+
await this.eventLog.notify(conversationId, seq);
|
|
840
|
+
}
|
|
841
|
+
for (const a of skipped.network) {
|
|
842
|
+
await this.events.emit("approval.decided", {
|
|
843
|
+
id: a.id,
|
|
844
|
+
orgId: a.orgId,
|
|
845
|
+
conversationId: a.conversationId,
|
|
846
|
+
runId: a.runId,
|
|
847
|
+
status: "skipped",
|
|
848
|
+
});
|
|
849
|
+
}
|
|
821
850
|
}
|
|
822
851
|
/**
|
|
823
852
|
* Writes the message (preceded by its `model_switched` when it switches) inside `t` and updates
|
|
@@ -826,7 +855,7 @@ let ConversationsService = class ConversationsService {
|
|
|
826
855
|
* questions its author may answer (reply-while-question spec §8.1): `skipped` and the highest
|
|
827
856
|
* seq their events took. The caller notifies and emits `question.answered` after commit.
|
|
828
857
|
*/
|
|
829
|
-
async writeMessage(orgId, conversationId, accountId, input, next, extra, blocks, invoked) {
|
|
858
|
+
async writeMessage(orgId, conversationId, accountId, input, next, extra, blocks, invoked, internal = {}) {
|
|
830
859
|
const events = [];
|
|
831
860
|
if (next !== null) {
|
|
832
861
|
events.push({
|
|
@@ -843,13 +872,14 @@ let ConversationsService = class ConversationsService {
|
|
|
843
872
|
senderName: input.senderName,
|
|
844
873
|
browser: { timeZone: input.timeZone, locale: input.locale },
|
|
845
874
|
im: input.im,
|
|
875
|
+
timeZoneOverride: internal.timeZoneOverride,
|
|
846
876
|
});
|
|
847
|
-
events.push(this.userMessage(accountId, input, extra, blocks, invoked, context));
|
|
877
|
+
events.push(this.userMessage(accountId, input, extra, blocks, invoked, context, internal.schedule));
|
|
848
878
|
const { events: written, fresh } = await this.eventLog.appendInReport(conversationId, events);
|
|
849
879
|
const message = written.at(-1);
|
|
850
880
|
const skips = fresh.at(-1) === true
|
|
851
|
-
? await this.
|
|
852
|
-
: {
|
|
881
|
+
? await this.skipWaitsIn(conversationId, accountId, message.seq)
|
|
882
|
+
: { skipped: NO_REPLY_SKIPS, toSeq: null };
|
|
853
883
|
if (next !== null) {
|
|
854
884
|
const t = this.db.db;
|
|
855
885
|
// the cache follows the log (a retried message's switch may be an old, deduped event that a
|
|
@@ -860,7 +890,7 @@ let ConversationsService = class ConversationsService {
|
|
|
860
890
|
.where("id", "=", conversationId)
|
|
861
891
|
.execute();
|
|
862
892
|
}
|
|
863
|
-
return { events: written, skipped: skips.
|
|
893
|
+
return { events: written, skipped: skips.skipped, skippedToSeq: skips.toSeq };
|
|
864
894
|
}
|
|
865
895
|
/**
|
|
866
896
|
* Renders the message's skill invocation (phase D), or undefined when it has none. Resolved
|
|
@@ -905,7 +935,7 @@ let ConversationsService = class ConversationsService {
|
|
|
905
935
|
return [];
|
|
906
936
|
return this.attachments.bindForMessage(orgId, conversationId, accountId, files);
|
|
907
937
|
}
|
|
908
|
-
userMessage(accountId, input, extra, fileBlocks, invoked, context) {
|
|
938
|
+
userMessage(accountId, input, extra, fileBlocks, invoked, context, schedule) {
|
|
909
939
|
// a skill invocation's rendered text replaces the typed arguments as content[0]
|
|
910
940
|
const text = invoked?.text ?? input.text;
|
|
911
941
|
return {
|
|
@@ -926,6 +956,7 @@ let ConversationsService = class ConversationsService {
|
|
|
926
956
|
...(input.clientMessageId !== undefined && { clientMessageId: input.clientMessageId }),
|
|
927
957
|
...(input.retryOf !== undefined && { retryOf: input.retryOf }),
|
|
928
958
|
...(invoked !== undefined && { skill: invoked.skill }),
|
|
959
|
+
...(schedule !== undefined && { schedule }),
|
|
929
960
|
},
|
|
930
961
|
};
|
|
931
962
|
}
|
|
@@ -988,7 +1019,7 @@ __decorate([
|
|
|
988
1019
|
], ConversationsService.prototype, "postIn", null);
|
|
989
1020
|
__decorate([
|
|
990
1021
|
Transactional({ propagation: "mandatory" })
|
|
991
|
-
], ConversationsService.prototype, "
|
|
1022
|
+
], ConversationsService.prototype, "skipWaitsIn", null);
|
|
992
1023
|
__decorate([
|
|
993
1024
|
Transactional({ propagation: "mandatory" })
|
|
994
1025
|
], ConversationsService.prototype, "writeMessage", null);
|
|
@@ -1010,7 +1041,8 @@ ConversationsService = __decorate([
|
|
|
1010
1041
|
__param(10, Inject(BackgroundTaskStopper)),
|
|
1011
1042
|
__param(11, Inject(ConversationDevices)),
|
|
1012
1043
|
__param(12, Inject(QuestionsService)),
|
|
1013
|
-
__param(13, Inject(
|
|
1014
|
-
__param(14, Inject(
|
|
1044
|
+
__param(13, Inject(ApprovalsService)),
|
|
1045
|
+
__param(14, Inject(KernelEvents)),
|
|
1046
|
+
__param(15, Inject(TransactionHost))
|
|
1015
1047
|
], ConversationsService);
|
|
1016
1048
|
export { ConversationsService };
|