@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、loop mount 和固定 3 GiB 校验后,daemon 才发送 `sandbox.ready`。RuntimeSession 使用稳定路径
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、loop unmount、backing image 和 NFS parent fsync;完成后
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
- "workspace_writer_freeze_v1",
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 materialization = readWorkspaceMaterializationMarker(this.options.sandboxId, sessionId);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botlearn-course/daemon",
3
- "version": "0.0.20-beta.12",
3
+ "version": "0.0.20-beta.14",
4
4
  "description": "Lightweight BotLearn Course daemon: run course tasks on your own machine with your own agent runtime (BYOA).",
5
5
  "type": "module",
6
6
  "bin": {