@botlearn-course/daemon 0.0.20-beta.12 → 0.0.20-beta.14
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/README.md
CHANGED
|
@@ -48,10 +48,10 @@ daemon,由 root-owned 固定 launcher 清空附加组后直接降权为 `user`
|
|
|
48
48
|
课程任务或 workspace shell。
|
|
49
49
|
|
|
50
50
|
veFaaS Origin 的托管 workspace 使用用户级 NAS backing image。root bootstrap 完成 NFS、marker、
|
|
51
|
-
ext4
|
|
51
|
+
ext4、`fuse2fs` mount 和固定 3 GiB 校验后,daemon 才发送 `sandbox.ready`。RuntimeSession 使用稳定路径
|
|
52
52
|
`/workspace/sessions/{runtime_session_id}/workspace`,Sandbox generation 只参与写入隔离。磁盘写满
|
|
53
53
|
统一上报 `workspace_user_quota_exceeded`。pause 和 cleanup 进入 drain 后,daemon 先停止 runtime
|
|
54
|
-
writer,再通过 root launcher 执行 ext4 sync
|
|
54
|
+
writer,再通过 root launcher 执行 ext4 sync、`fuse2fs` unmount、backing image 和 NFS parent fsync;完成后
|
|
55
55
|
才发送 `sandbox.drained` 并退出。
|
|
56
56
|
|
|
57
57
|
## 支持的 runtime
|
|
@@ -3,6 +3,8 @@ import type { WorkspaceScanMeasurement } from "./file-candidates.js";
|
|
|
3
3
|
import { type RuntimeSkillProviderFactory } from "./runtime-skills.js";
|
|
4
4
|
import { type PersistentSessionExecution, type PreparedPersistentTurn, type RunReportingClient } from "./run-dispatcher.js";
|
|
5
5
|
import type { CourseRuntime, CourseRuntimeProfile, RunEvent, RunEventReceipt, RunFileCandidate, RunFileRecord, RunStartPayload } from "./types.js";
|
|
6
|
+
export declare function workspaceDurabilityCapabilities(usesNasWorkspace?: boolean): string[];
|
|
7
|
+
export declare function assertWorkspaceRestoreAllowed(requestedRestore: unknown, usesNasWorkspace?: boolean): void;
|
|
6
8
|
export interface AgentServiceSandboxOptions {
|
|
7
9
|
wsUrl: string;
|
|
8
10
|
sandboxId: string;
|
|
@@ -41,6 +41,18 @@ function agentServiceHttpBase(wsUrl) {
|
|
|
41
41
|
}
|
|
42
42
|
const RUNTIME_LOG_WINDOW_MS = 60_000;
|
|
43
43
|
const WORKSPACE_FILE_TRANSFER_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
44
|
+
export function workspaceDurabilityCapabilities(usesNasWorkspace = nasWorkspaceEnabled()) {
|
|
45
|
+
return [
|
|
46
|
+
"workspace_writer_freeze_v1",
|
|
47
|
+
"workspace_snapshot_v2",
|
|
48
|
+
...(usesNasWorkspace ? ["workspace_nas_v1"] : ["workspace_restore_v1"]),
|
|
49
|
+
];
|
|
50
|
+
}
|
|
51
|
+
export function assertWorkspaceRestoreAllowed(requestedRestore, usesNasWorkspace = nasWorkspaceEnabled()) {
|
|
52
|
+
if (usesNasWorkspace && requestedRestore !== null && requestedRestore !== undefined) {
|
|
53
|
+
throw new Error("workspace_restore_forbidden_for_nas");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
44
56
|
const DISABLED_RUNTIME_LOG_POLICY = {
|
|
45
57
|
enabled: false,
|
|
46
58
|
maxEventBytes: 4096,
|
|
@@ -872,10 +884,7 @@ export class AgentServiceSandboxClient {
|
|
|
872
884
|
protocol_versions: [AGENT_SERVICE_WS_SCHEMA],
|
|
873
885
|
capabilities: [
|
|
874
886
|
WORKSPACE_FILE_READ_BINARY_CAPABILITY,
|
|
875
|
-
|
|
876
|
-
"workspace_snapshot_v2",
|
|
877
|
-
"workspace_restore_v1",
|
|
878
|
-
...(nasWorkspaceEnabled() ? ["workspace_nas_v1"] : []),
|
|
887
|
+
...workspaceDurabilityCapabilities(),
|
|
879
888
|
...(workspaceCopyV1Supported() ? ["workspace_copy_v1"] : []),
|
|
880
889
|
],
|
|
881
890
|
workspace_snapshot_policy: workspaceSnapshotPolicyCapability(),
|
|
@@ -1059,6 +1068,7 @@ export class AgentServiceSandboxClient {
|
|
|
1059
1068
|
const requestedWorkspaceRef = frame.payload.workspace_ref;
|
|
1060
1069
|
const requestedCopy = frame.payload.workspace_copy;
|
|
1061
1070
|
const requestedRestore = frame.payload.workspace_restore;
|
|
1071
|
+
assertWorkspaceRestoreAllowed(requestedRestore);
|
|
1062
1072
|
const requestedCopyRecord = requestedCopy && typeof requestedCopy === "object"
|
|
1063
1073
|
? requestedCopy
|
|
1064
1074
|
: undefined;
|
|
@@ -1344,10 +1354,14 @@ export class AgentServiceSandboxClient {
|
|
|
1344
1354
|
}
|
|
1345
1355
|
this.state.sessions[sessionId] = session;
|
|
1346
1356
|
this.persist();
|
|
1347
|
-
const
|
|
1357
|
+
const usesNasWorkspace = nasWorkspaceEnabled();
|
|
1358
|
+
const materialization = usesNasWorkspace
|
|
1359
|
+
? null
|
|
1360
|
+
: readWorkspaceMaterializationMarker(this.options.sandboxId, sessionId);
|
|
1348
1361
|
await this.sendSessionFrame("session.opened", sessionId, {
|
|
1349
1362
|
workspace_ref: session.workspaceRef,
|
|
1350
1363
|
native_session_id: session.nativeSessionId,
|
|
1364
|
+
workspace_authority: usesNasWorkspace ? "nas" : "snapshot",
|
|
1351
1365
|
...(materialization
|
|
1352
1366
|
? {
|
|
1353
1367
|
workspace_marker_version: 1,
|
package/package.json
CHANGED