@botlearn-course/daemon 0.0.7 → 0.0.9

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.
@@ -1,28 +1,36 @@
1
- export declare const AGENT_SERVICE_WS_SCHEMA: "botlearn-agent-sandbox-ws/0.1";
2
- export declare const AGENT_SERVICE_WS_SUBPROTOCOL: "botlearn-agent-sandbox.v1";
3
- export type SandboxFrameType = "session.hello" | "session.sync" | "turn.start" | "turn.cancel" | "session.drain" | "session.shutdown" | "event.ack" | "turn.file.upload_grant" | "auth.rotate" | "ping" | "session.ready" | "session.heartbeat" | "command.ack" | "turn.event" | "turn.file.prepare" | "turn.file.committed" | "session.drained" | "pong" | "protocol.error";
1
+ export declare const AGENT_SERVICE_WS_SCHEMA: "botlearn-agent-sandbox-ws/0.2";
2
+ export declare const AGENT_SERVICE_WS_SUBPROTOCOL: "botlearn-agent-sandbox.v2";
3
+ export type SandboxFrameType = "sandbox.hello" | "sandbox.sync" | "session.open" | "session.activate" | "turn.start" | "turn.cancel" | "session.close" | "sandbox.drain" | "sandbox.shutdown" | "event.ack" | "turn.file.upload_grant" | "auth.rotate" | "ping" | "sandbox.ready" | "sandbox.heartbeat" | "command.ack" | "session.opened" | "session.closed" | "turn.event" | "turn.file.prepare" | "turn.file.committed" | "sandbox.drained" | "pong" | "protocol.error";
4
+ export declare class UnsupportedSandboxProtocolError extends Error {
5
+ readonly schemaVersion: unknown;
6
+ constructor(schemaVersion: unknown);
7
+ }
4
8
  export interface SandboxFrame {
5
9
  schema_version: typeof AGENT_SERVICE_WS_SCHEMA;
6
10
  type: SandboxFrameType;
7
11
  frame_id: string;
8
- session_id: string;
9
- session_generation: number;
12
+ sandbox_id: string;
13
+ sandbox_generation: number;
10
14
  connection_epoch: number;
11
15
  seq: number;
12
16
  sent_at: string;
17
+ runtime_session_id: string | null;
13
18
  agent_run_id: string | null;
14
19
  worker_attempt: number | null;
20
+ activation_id: string | null;
15
21
  payload: Record<string, unknown>;
16
22
  }
17
23
  export declare function parseSandboxFrame(raw: string, maxBytes?: number): SandboxFrame;
18
24
  export declare function createSandboxFrame(input: {
19
25
  type: SandboxFrameType;
20
- sessionId: string;
21
- sessionGeneration: number;
26
+ sandboxId: string;
27
+ sandboxGeneration: number;
22
28
  connectionEpoch: number;
23
29
  seq: number;
24
30
  payload?: Record<string, unknown>;
31
+ runtimeSessionId?: string;
25
32
  agentRunId?: string;
26
33
  workerAttempt?: number;
34
+ activationId?: string;
27
35
  frameId?: string;
28
36
  }): SandboxFrame;
@@ -1,27 +1,41 @@
1
1
  import { randomUUID } from "node:crypto";
2
- export const AGENT_SERVICE_WS_SCHEMA = "botlearn-agent-sandbox-ws/0.1";
3
- export const AGENT_SERVICE_WS_SUBPROTOCOL = "botlearn-agent-sandbox.v1";
2
+ export const AGENT_SERVICE_WS_SCHEMA = "botlearn-agent-sandbox-ws/0.2";
3
+ export const AGENT_SERVICE_WS_SUBPROTOCOL = "botlearn-agent-sandbox.v2";
4
4
  const FRAME_TYPES = new Set([
5
- "session.hello",
6
- "session.sync",
5
+ "sandbox.hello",
6
+ "sandbox.sync",
7
+ "session.open",
8
+ "session.activate",
7
9
  "turn.start",
8
10
  "turn.cancel",
9
- "session.drain",
10
- "session.shutdown",
11
+ "session.close",
12
+ "sandbox.drain",
13
+ "sandbox.shutdown",
11
14
  "event.ack",
12
15
  "turn.file.upload_grant",
13
16
  "auth.rotate",
14
17
  "ping",
15
- "session.ready",
16
- "session.heartbeat",
18
+ "sandbox.ready",
19
+ "sandbox.heartbeat",
17
20
  "command.ack",
21
+ "session.opened",
22
+ "session.closed",
18
23
  "turn.event",
19
24
  "turn.file.prepare",
20
25
  "turn.file.committed",
21
- "session.drained",
26
+ "sandbox.drained",
22
27
  "pong",
23
28
  "protocol.error",
24
29
  ]);
30
+ /** SESSION 帧:必须带 runtime_session_id;禁止 run/attempt。session.activate 额外必须带 activation_id。 */
31
+ const SESSION_TYPES = new Set([
32
+ "session.open",
33
+ "session.activate",
34
+ "session.close",
35
+ "session.opened",
36
+ "session.closed",
37
+ ]);
38
+ /** TURN 帧:必须带 runtime_session_id + agent_run_id + worker_attempt + activation_id 四元组。 */
25
39
  const TURN_TYPES = new Set([
26
40
  "turn.start",
27
41
  "turn.cancel",
@@ -35,22 +49,39 @@ const FRAME_KEYS = new Set([
35
49
  "schema_version",
36
50
  "type",
37
51
  "frame_id",
38
- "session_id",
39
- "session_generation",
52
+ "sandbox_id",
53
+ "sandbox_generation",
40
54
  "connection_epoch",
41
55
  "seq",
42
56
  "sent_at",
57
+ "runtime_session_id",
43
58
  "agent_run_id",
44
59
  "worker_attempt",
60
+ "activation_id",
45
61
  "payload",
46
62
  ]);
47
63
  const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
64
+ export class UnsupportedSandboxProtocolError extends Error {
65
+ schemaVersion;
66
+ constructor(schemaVersion) {
67
+ super("unsupported sandbox WebSocket schema");
68
+ this.schemaVersion = schemaVersion;
69
+ this.name = "UnsupportedSandboxProtocolError";
70
+ }
71
+ }
48
72
  function positiveInteger(value, label) {
49
73
  if (!Number.isInteger(value) || value < 1) {
50
74
  throw new Error(`${label} must be a positive integer`);
51
75
  }
52
76
  return value;
53
77
  }
78
+ function nullableString(value, label) {
79
+ if (value === null || value === undefined)
80
+ return null;
81
+ if (typeof value !== "string")
82
+ throw new Error(`${label} must be a string or null`);
83
+ return value;
84
+ }
54
85
  export function parseSandboxFrame(raw, maxBytes = 262_144) {
55
86
  if (Buffer.byteLength(raw, "utf8") > maxBytes)
56
87
  throw new Error("frame exceeds size limit");
@@ -64,33 +95,60 @@ export function parseSandboxFrame(raw, maxBytes = 262_144) {
64
95
  throw new Error(`unknown sandbox WebSocket frame field: ${key}`);
65
96
  }
66
97
  if (value.schema_version !== AGENT_SERVICE_WS_SCHEMA) {
67
- throw new Error("unsupported sandbox WebSocket schema");
98
+ throw new UnsupportedSandboxProtocolError(value.schema_version);
68
99
  }
69
100
  if (typeof value.type !== "string" || !FRAME_TYPES.has(value.type)) {
70
101
  throw new Error("unknown sandbox WebSocket frame type");
71
102
  }
72
103
  const type = value.type;
73
- const agentRunId = typeof value.agent_run_id === "string" ? value.agent_run_id : null;
104
+ const runtimeSessionId = nullableString(value.runtime_session_id, "runtime_session_id");
105
+ const agentRunId = nullableString(value.agent_run_id, "agent_run_id");
74
106
  const workerAttempt = value.worker_attempt == null
75
107
  ? null
76
108
  : positiveInteger(value.worker_attempt, "worker_attempt");
77
- if (TURN_TYPES.has(type) && (!agentRunId || workerAttempt === null)) {
78
- throw new Error(`${type} requires turn fencing fields`);
109
+ const activationId = nullableString(value.activation_id, "activation_id");
110
+ if (activationId !== null && (activationId.length < 1 || activationId.length > 120)) {
111
+ throw new Error("activation_id length is invalid");
112
+ }
113
+ if (TURN_TYPES.has(type)) {
114
+ if (!runtimeSessionId || !agentRunId || workerAttempt === null || !activationId) {
115
+ throw new Error(`${type} requires the full turn scope`);
116
+ }
79
117
  }
80
- if (!TURN_TYPES.has(type) && (agentRunId !== null || workerAttempt !== null)) {
81
- throw new Error(`${type} cannot carry turn fencing fields`);
118
+ else if (SESSION_TYPES.has(type)) {
119
+ if (!runtimeSessionId)
120
+ throw new Error(`${type} requires runtime_session_id`);
121
+ if (agentRunId !== null || workerAttempt !== null) {
122
+ throw new Error(`${type} cannot carry turn fencing fields`);
123
+ }
124
+ if (type === "session.activate") {
125
+ if (!activationId)
126
+ throw new Error("session.activate requires activation_id");
127
+ }
128
+ else if (activationId !== null) {
129
+ throw new Error(`${type} cannot carry activation_id`);
130
+ }
131
+ }
132
+ else if (runtimeSessionId !== null ||
133
+ agentRunId !== null ||
134
+ workerAttempt !== null ||
135
+ activationId !== null) {
136
+ throw new Error(`${type} cannot carry session or turn scope fields`);
82
137
  }
83
138
  if (!value.payload || typeof value.payload !== "object" || Array.isArray(value.payload)) {
84
139
  throw new Error("frame payload must be an object");
85
140
  }
86
- for (const key of ["frame_id", "session_id", "sent_at"]) {
141
+ for (const key of ["frame_id", "sandbox_id", "sent_at"]) {
87
142
  if (typeof value[key] !== "string" || !value[key])
88
143
  throw new Error(`${key} is required`);
89
144
  }
90
145
  if (value.frame_id.length > 120)
91
146
  throw new Error("frame_id is too long");
92
- if (!UUID_PATTERN.test(value.session_id))
93
- throw new Error("session_id must be a UUID");
147
+ if (!UUID_PATTERN.test(value.sandbox_id))
148
+ throw new Error("sandbox_id must be a UUID");
149
+ if (runtimeSessionId !== null && !UUID_PATTERN.test(runtimeSessionId)) {
150
+ throw new Error("runtime_session_id must be a UUID");
151
+ }
94
152
  if (agentRunId !== null && !UUID_PATTERN.test(agentRunId)) {
95
153
  throw new Error("agent_run_id must be a UUID");
96
154
  }
@@ -100,13 +158,15 @@ export function parseSandboxFrame(raw, maxBytes = 262_144) {
100
158
  schema_version: AGENT_SERVICE_WS_SCHEMA,
101
159
  type,
102
160
  frame_id: value.frame_id,
103
- session_id: value.session_id,
104
- session_generation: positiveInteger(value.session_generation, "session_generation"),
161
+ sandbox_id: value.sandbox_id,
162
+ sandbox_generation: positiveInteger(value.sandbox_generation, "sandbox_generation"),
105
163
  connection_epoch: positiveInteger(value.connection_epoch, "connection_epoch"),
106
164
  seq: positiveInteger(value.seq, "seq"),
107
165
  sent_at: value.sent_at,
166
+ runtime_session_id: runtimeSessionId,
108
167
  agent_run_id: agentRunId,
109
168
  worker_attempt: workerAttempt,
169
+ activation_id: activationId,
110
170
  payload: value.payload,
111
171
  };
112
172
  }
@@ -115,13 +175,15 @@ export function createSandboxFrame(input) {
115
175
  schema_version: AGENT_SERVICE_WS_SCHEMA,
116
176
  type: input.type,
117
177
  frame_id: input.frameId ?? `frm_${randomUUID().replaceAll("-", "")}`,
118
- session_id: input.sessionId,
119
- session_generation: input.sessionGeneration,
178
+ sandbox_id: input.sandboxId,
179
+ sandbox_generation: input.sandboxGeneration,
120
180
  connection_epoch: input.connectionEpoch,
121
181
  seq: input.seq,
122
182
  sent_at: new Date().toISOString(),
183
+ runtime_session_id: input.runtimeSessionId ?? null,
123
184
  agent_run_id: input.agentRunId ?? null,
124
185
  worker_attempt: input.workerAttempt ?? null,
186
+ activation_id: input.activationId ?? null,
125
187
  payload: input.payload ?? {},
126
188
  };
127
189
  return parseSandboxFrame(JSON.stringify(frame));
package/dist/cli.js CHANGED
@@ -5,7 +5,7 @@ import { hostname } from "node:os";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { authFilePath, clearAuth, machineFingerprint, readAuth, writeAuth } from "./auth-store.js";
7
7
  import { AgentServiceRunClient } from "./agent-service-client.js";
8
- import { AgentServiceSessionClient } from "./agent-service-session.js";
8
+ import { AgentServiceSandboxClient } from "./agent-service-sandbox.js";
9
9
  import { CourseClient, isAuthFailure, loginCourseDaemon } from "./course-client.js";
10
10
  import { runCourseDoctor } from "./doctor.js";
11
11
  import { log } from "./log.js";
@@ -16,16 +16,6 @@ import { clearAgentServiceControlEnv } from "./runtime-env.js";
16
16
  import { RUNTIME_MODULES, detectAvailableRuntimeIds, fakeRuntimeEnabled, } from "./runtimes/index.js";
17
17
  const pkg = createRequire(import.meta.url)("../package.json");
18
18
  const SESSION_BOOTSTRAP_MAX_BYTES = 64 * 1024;
19
- const SESSION_RUNTIME_ENV_KEYS = new Set([
20
- "OPENAI_API_KEY",
21
- "OPENAI_BASE_URL",
22
- "ANTHROPIC_API_KEY",
23
- "ANTHROPIC_BASE_URL",
24
- "DEEPSEEK_API_KEY",
25
- "DEEPSEEK_BASE_URL",
26
- "GEMINI_API_KEY",
27
- "GEMINI_BASE_URL",
28
- ]);
29
19
  const HELP = `botlearn-course-daemon ${pkg.version} — run BotLearn Course tasks on your own machine (BYOA)
30
20
 
31
21
  Usage:
@@ -57,8 +47,8 @@ Agent Service sandbox environment:
57
47
  BOTLEARN_AGENT_SERVICE_RUN_TOKEN
58
48
  BOTLEARN_AGENT_SERVICE_WORKER_ID
59
49
  BOTLEARN_AGENT_SERVICE_WS_URL
60
- BOTLEARN_AGENT_SERVICE_RUNTIME_SESSION_ID
61
- BOTLEARN_AGENT_SERVICE_SESSION_TOKEN`;
50
+ BOTLEARN_AGENT_SERVICE_SANDBOX_ID
51
+ BOTLEARN_AGENT_SERVICE_SANDBOX_TOKEN`;
62
52
  // ---------------------------------------------------------------
63
53
  // flag parser(极简:--k v / --k=v / 布尔开关)
64
54
  // ---------------------------------------------------------------
@@ -304,56 +294,41 @@ async function cmdAgentServiceRun() {
304
294
  }
305
295
  return 0;
306
296
  }
307
- async function readSessionBootstrapFromStdin() {
297
+ async function readSandboxBootstrapFromStdin() {
308
298
  const chunks = [];
309
299
  let size = 0;
310
300
  for await (const chunk of process.stdin) {
311
301
  const bytes = Buffer.from(chunk);
312
302
  size += bytes.length;
313
303
  if (size > SESSION_BOOTSTRAP_MAX_BYTES) {
314
- throw new Error("Agent Service session bootstrap exceeds size limit");
304
+ throw new Error("Agent Service sandbox bootstrap exceeds size limit");
315
305
  }
316
306
  chunks.push(bytes);
317
307
  }
318
308
  const raw = Buffer.concat(chunks);
319
309
  try {
320
310
  const parsed = JSON.parse(raw.toString("utf8"));
321
- if (parsed.schemaVersion !== "agent-service-session-bootstrap/0.1") {
322
- throw new Error("Agent Service session bootstrap schema is unsupported");
311
+ if (parsed.schema !== "agent-service-sandbox-bootstrap/0.2") {
312
+ throw new Error("Agent Service sandbox bootstrap schema is unsupported");
323
313
  }
324
- const runtimeEnv = {};
325
314
  if (parsed.runtimeEnv !== undefined) {
326
- if (!parsed.runtimeEnv ||
327
- typeof parsed.runtimeEnv !== "object" ||
328
- Array.isArray(parsed.runtimeEnv)) {
329
- throw new Error("Agent Service session bootstrap runtimeEnv is invalid");
330
- }
331
- for (const [key, value] of Object.entries(parsed.runtimeEnv)) {
332
- if (!SESSION_RUNTIME_ENV_KEYS.has(key) ||
333
- typeof value !== "string" ||
334
- value.length < 1 ||
335
- value.length > 8192) {
336
- throw new Error(`Agent Service session bootstrap runtime env is forbidden: ${key}`);
337
- }
338
- runtimeEnv[key] = value;
339
- }
315
+ throw new Error("Agent Service sandbox bootstrap runtimeEnv is unsupported; use session.activate");
340
316
  }
341
317
  const wsUrl = parsed.wsUrl;
342
- const runtimeSessionId = parsed.runtimeSessionId;
343
- const sessionToken = parsed.sessionToken;
318
+ const sandboxId = parsed.sandboxId;
319
+ const sandboxToken = parsed.sandboxToken;
344
320
  if (typeof wsUrl !== "string" ||
345
321
  !/^wss?:\/\//.test(wsUrl) ||
346
- typeof runtimeSessionId !== "string" ||
347
- !runtimeSessionId ||
348
- typeof sessionToken !== "string" ||
349
- !sessionToken) {
350
- throw new Error("Agent Service session bootstrap is incomplete");
322
+ typeof sandboxId !== "string" ||
323
+ !sandboxId ||
324
+ typeof sandboxToken !== "string" ||
325
+ !sandboxToken) {
326
+ throw new Error("Agent Service sandbox bootstrap is incomplete");
351
327
  }
352
328
  return {
353
329
  wsUrl,
354
- runtimeSessionId,
355
- sessionToken,
356
- ...(Object.keys(runtimeEnv).length > 0 ? { runtimeEnv } : {}),
330
+ sandboxId,
331
+ sandboxToken,
357
332
  };
358
333
  }
359
334
  finally {
@@ -364,16 +339,15 @@ async function readSessionBootstrapFromStdin() {
364
339
  }
365
340
  async function cmdAgentServiceSession(args) {
366
341
  const bootstrap = args.flags["bootstrap-stdin"] === true
367
- ? await readSessionBootstrapFromStdin()
342
+ ? await readSandboxBootstrapFromStdin()
368
343
  : {
369
344
  wsUrl: process.env.BOTLEARN_AGENT_SERVICE_WS_URL,
370
- runtimeSessionId: process.env.BOTLEARN_AGENT_SERVICE_RUNTIME_SESSION_ID,
371
- sessionToken: process.env.BOTLEARN_AGENT_SERVICE_SESSION_TOKEN,
372
- runtimeEnv: undefined,
345
+ sandboxId: process.env.BOTLEARN_AGENT_SERVICE_SANDBOX_ID,
346
+ sandboxToken: process.env.BOTLEARN_AGENT_SERVICE_SANDBOX_TOKEN,
373
347
  };
374
- const { wsUrl, runtimeSessionId, sessionToken } = bootstrap;
375
- if (!wsUrl || !runtimeSessionId || !sessionToken) {
376
- console.error("Agent Service sandbox session environment is incomplete");
348
+ const { wsUrl, sandboxId, sandboxToken } = bootstrap;
349
+ if (!wsUrl || !sandboxId || !sandboxToken) {
350
+ console.error("Agent Service sandbox environment is incomplete");
377
351
  return 1;
378
352
  }
379
353
  augmentProcessPath();
@@ -383,11 +357,10 @@ async function cmdAgentServiceSession(args) {
383
357
  continue;
384
358
  runtimes.set(mod.id, mod.create());
385
359
  }
386
- const client = new AgentServiceSessionClient({
360
+ const client = new AgentServiceSandboxClient({
387
361
  wsUrl,
388
- sessionId: runtimeSessionId,
389
- sessionToken,
390
- ...(bootstrap.runtimeEnv ? { runtimeEnv: bootstrap.runtimeEnv } : {}),
362
+ sandboxId,
363
+ sandboxToken,
391
364
  runtimes,
392
365
  daemonVersion: pkg.version,
393
366
  });
@@ -43,11 +43,11 @@ export class CourseClient {
43
43
  setAccessToken(token) {
44
44
  this.accessToken = token;
45
45
  }
46
- // courseApiUrl 可能是 host 根,也可能已带 /api/v1 —— 去重避免拼出 /api/v1/api/v1。
46
+ // courseApiUrl 可能是 host 根,也可能已带 /course/v1 —— 去重避免拼出 /course/v1/course/v1。
47
47
  url(p) {
48
48
  const base = this.baseUrl.replace(/\/+$/, "");
49
- if (base.endsWith("/api/v1") && p.startsWith("/api/v1/")) {
50
- return `${base}${p.slice("/api/v1".length)}`;
49
+ if (base.endsWith("/course/v1") && p.startsWith("/course/v1/")) {
50
+ return `${base}${p.slice("/course/v1".length)}`;
51
51
  }
52
52
  return `${base}${p}`;
53
53
  }
@@ -98,18 +98,18 @@ export class CourseClient {
98
98
  }
99
99
  /** 领取下一个分配给本 daemon 的 queued run(无则返回 null)。 */
100
100
  async claimNextRun() {
101
- return this.request("GET", "/api/v1/daemon/runs/next");
101
+ return this.request("GET", "/course/v1/daemon/runs/next");
102
102
  }
103
103
  async postEvent(agentRunId, event) {
104
104
  const credentials = [this.accessToken, this.refreshToken].filter((value) => typeof value === "string");
105
105
  const sanitized = redactSecretsDeep(event, 8, credentials);
106
- await this.request("POST", `/api/v1/daemon/runs/${agentRunId}/events`, sanitized, event.trace_id);
106
+ await this.request("POST", `/course/v1/daemon/runs/${agentRunId}/events`, sanitized, event.trace_id);
107
107
  }
108
108
  async postFile(agentRunId, file) {
109
- return this.request("POST", `/api/v1/daemon/runs/${agentRunId}/files`, file);
109
+ return this.request("POST", `/course/v1/daemon/runs/${agentRunId}/files`, file);
110
110
  }
111
111
  async getRunRuntimeProfile(agentRunId) {
112
- return this.request("GET", `/api/v1/daemon/runs/${agentRunId}/runtime-profile`);
112
+ return this.request("GET", `/course/v1/daemon/runs/${agentRunId}/runtime-profile`);
113
113
  }
114
114
  }
115
115
  function authFromResponse(baseUrl, raw) {
@@ -131,7 +131,7 @@ function authFromResponse(baseUrl, raw) {
131
131
  }
132
132
  export async function loginCourseDaemon(opts) {
133
133
  const client = new CourseClient(opts.courseApiUrl, "");
134
- const raw = await client.fetchJson("POST", "/api/v1/daemon/login", {
134
+ const raw = await client.fetchJson("POST", "/course/v1/daemon/login", {
135
135
  code: opts.code,
136
136
  label: opts.label ?? "",
137
137
  machine_fingerprint: opts.machineFingerprint,
@@ -141,6 +141,6 @@ export async function loginCourseDaemon(opts) {
141
141
  }
142
142
  export async function refreshCourseDaemonSession(courseApiUrl, refreshToken) {
143
143
  const client = new CourseClient(courseApiUrl, "");
144
- const raw = await client.fetchJson("POST", "/api/v1/daemon/session", { refresh_token: refreshToken }, null);
144
+ const raw = await client.fetchJson("POST", "/course/v1/daemon/session", { refresh_token: refreshToken }, null);
145
145
  return authFromResponse(courseApiUrl, raw);
146
146
  }
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@ export * from "./types.js";
6
6
  export * from "./auth-store.js";
7
7
  export * from "./course-client.js";
8
8
  export * from "./agent-service-client.js";
9
- export * from "./agent-service-session.js";
9
+ export * from "./agent-service-sandbox.js";
10
10
  export * from "./agent-service-ws-protocol.js";
11
11
  export * from "./run-dispatcher.js";
12
12
  export * from "./run-queue.js";
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ export * from "./types.js";
6
6
  export * from "./auth-store.js";
7
7
  export * from "./course-client.js";
8
8
  export * from "./agent-service-client.js";
9
- export * from "./agent-service-session.js";
9
+ export * from "./agent-service-sandbox.js";
10
10
  export * from "./agent-service-ws-protocol.js";
11
11
  export * from "./run-dispatcher.js";
12
12
  export * from "./run-queue.js";
@@ -18,6 +18,7 @@ export interface PreparedPersistentTurn {
18
18
  export interface PersistentSessionExecution {
19
19
  prepareTurn(payload: RunStartPayload): PreparedPersistentTurn;
20
20
  persistNativeSession(sessionId: string): void;
21
+ finishTurn(payload: RunStartPayload): void;
21
22
  }
22
23
  export interface RunReportingClient {
23
24
  postEvent(agentRunId: string, event: RunEvent): Promise<void>;
@@ -52,6 +53,8 @@ export declare class RunDispatcher {
52
53
  cancel(agentRunId: string): boolean;
53
54
  cancelAll(): void;
54
55
  get activeCount(): number;
56
+ /** Wait until the selected runs have left both the active and queued sets. */
57
+ waitForRuns(agentRunIds: Iterable<string>, timeoutMs: number): Promise<boolean>;
55
58
  /** 等待所有 run(含排队中的)结束;超时返回 false。 */
56
59
  drain(timeoutMs: number): Promise<boolean>;
57
60
  private execute;