@rivet-dev/agentos-runtime-core 0.0.0-codex-actor-plugin-contract-coverage.115ca8a → 0.0.0-eve-integration.9df6f34

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.
Files changed (240) hide show
  1. package/README.md +1 -1
  2. package/commands/[ +0 -0
  3. package/commands/_stubs +0 -0
  4. package/commands/acl_tools +0 -0
  5. package/commands/arch +0 -0
  6. package/commands/attr +0 -0
  7. package/commands/awk +0 -0
  8. package/commands/b2sum +0 -0
  9. package/commands/base32 +0 -0
  10. package/commands/base64 +0 -0
  11. package/commands/basename +0 -0
  12. package/commands/basenc +0 -0
  13. package/commands/bash +0 -0
  14. package/commands/bc +0 -0
  15. package/commands/cat +0 -0
  16. package/commands/chacl +0 -0
  17. package/commands/chcon +0 -0
  18. package/commands/chgrp +0 -0
  19. package/commands/chmod +0 -0
  20. package/commands/chown +0 -0
  21. package/commands/chroot +0 -0
  22. package/commands/cksum +0 -0
  23. package/commands/cmp +0 -0
  24. package/commands/column +0 -0
  25. package/commands/comm +0 -0
  26. package/commands/cp +0 -0
  27. package/commands/curl +0 -0
  28. package/commands/cut +0 -0
  29. package/commands/date +0 -0
  30. package/commands/dd +0 -0
  31. package/commands/df +0 -0
  32. package/commands/diff +0 -0
  33. package/commands/dir +0 -0
  34. package/commands/dircolors +0 -0
  35. package/commands/dirname +0 -0
  36. package/commands/du +0 -0
  37. package/commands/echo +0 -0
  38. package/commands/egrep +0 -0
  39. package/commands/env +0 -0
  40. package/commands/envsubst +0 -0
  41. package/commands/expand +0 -0
  42. package/commands/expr +0 -0
  43. package/commands/factor +0 -0
  44. package/commands/false +0 -0
  45. package/commands/fd +0 -0
  46. package/commands/fgrep +0 -0
  47. package/commands/file +0 -0
  48. package/commands/find +0 -0
  49. package/commands/findmnt +0 -0
  50. package/commands/fmt +0 -0
  51. package/commands/fold +0 -0
  52. package/commands/getent +0 -0
  53. package/commands/getfacl +0 -0
  54. package/commands/getfattr +0 -0
  55. package/commands/git +0 -0
  56. package/commands/git-receive-pack +0 -0
  57. package/commands/git-remote-http +0 -0
  58. package/commands/git-remote-https +0 -0
  59. package/commands/git-upload-archive +0 -0
  60. package/commands/git-upload-pack +0 -0
  61. package/commands/grep +0 -0
  62. package/commands/groups +0 -0
  63. package/commands/gunzip +0 -0
  64. package/commands/gzip +0 -0
  65. package/commands/head +0 -0
  66. package/commands/hostid +0 -0
  67. package/commands/hostname +0 -0
  68. package/commands/http-test +0 -0
  69. package/commands/id +0 -0
  70. package/commands/install +0 -0
  71. package/commands/join +0 -0
  72. package/commands/jq +0 -0
  73. package/commands/kill +0 -0
  74. package/commands/link +0 -0
  75. package/commands/ln +0 -0
  76. package/commands/logname +0 -0
  77. package/commands/ls +0 -0
  78. package/commands/md5sum +0 -0
  79. package/commands/mkdir +0 -0
  80. package/commands/mkfifo +0 -0
  81. package/commands/mknod +0 -0
  82. package/commands/mktemp +0 -0
  83. package/commands/more +0 -0
  84. package/commands/mount +0 -0
  85. package/commands/mv +0 -0
  86. package/commands/nice +0 -0
  87. package/commands/nl +0 -0
  88. package/commands/nohup +0 -0
  89. package/commands/nproc +0 -0
  90. package/commands/numfmt +0 -0
  91. package/commands/od +0 -0
  92. package/commands/paste +0 -0
  93. package/commands/pathchk +0 -0
  94. package/commands/pinky +0 -0
  95. package/commands/printenv +0 -0
  96. package/commands/printf +0 -0
  97. package/commands/ptx +0 -0
  98. package/commands/pwd +0 -0
  99. package/commands/readlink +0 -0
  100. package/commands/realpath +0 -0
  101. package/commands/rev +0 -0
  102. package/commands/rg +0 -0
  103. package/commands/rm +0 -0
  104. package/commands/rmdir +0 -0
  105. package/commands/runas +0 -0
  106. package/commands/runcon +0 -0
  107. package/commands/sed +0 -0
  108. package/commands/seq +0 -0
  109. package/commands/setfacl +0 -0
  110. package/commands/setfattr +0 -0
  111. package/commands/sh +0 -0
  112. package/commands/sha1sum +0 -0
  113. package/commands/sha224sum +0 -0
  114. package/commands/sha256sum +0 -0
  115. package/commands/sha384sum +0 -0
  116. package/commands/sha512sum +0 -0
  117. package/commands/shred +0 -0
  118. package/commands/shuf +0 -0
  119. package/commands/sleep +0 -0
  120. package/commands/sort +0 -0
  121. package/commands/spawn-test-host +0 -0
  122. package/commands/split +0 -0
  123. package/commands/sqlite3 +0 -0
  124. package/commands/ssh +0 -0
  125. package/commands/ssh-keysign +0 -0
  126. package/commands/ssh-sk-helper +0 -0
  127. package/commands/stat +0 -0
  128. package/commands/stdbuf +0 -0
  129. package/commands/strings +0 -0
  130. package/commands/stty +0 -0
  131. package/commands/su +0 -0
  132. package/commands/sum +0 -0
  133. package/commands/sync +0 -0
  134. package/commands/tac +0 -0
  135. package/commands/tail +0 -0
  136. package/commands/tar +0 -0
  137. package/commands/tee +0 -0
  138. package/commands/test +0 -0
  139. package/commands/timeout +0 -0
  140. package/commands/touch +0 -0
  141. package/commands/tr +0 -0
  142. package/commands/tree +0 -0
  143. package/commands/true +0 -0
  144. package/commands/truncate +0 -0
  145. package/commands/tsort +0 -0
  146. package/commands/tty +0 -0
  147. package/commands/uname +0 -0
  148. package/commands/unexpand +0 -0
  149. package/commands/uniq +0 -0
  150. package/commands/unlink +0 -0
  151. package/commands/unzip +0 -0
  152. package/commands/uptime +0 -0
  153. package/commands/users +0 -0
  154. package/commands/vdir +0 -0
  155. package/commands/wc +0 -0
  156. package/commands/wget +0 -0
  157. package/commands/which +0 -0
  158. package/commands/who +0 -0
  159. package/commands/whoami +0 -0
  160. package/commands/xargs +0 -0
  161. package/commands/xattr_tools +0 -0
  162. package/commands/xfs_io +0 -0
  163. package/commands/xu +0 -0
  164. package/commands/yes +0 -0
  165. package/commands/yq +0 -0
  166. package/commands/zcat +0 -0
  167. package/commands/zip +0 -0
  168. package/dist/binary.js +4 -3
  169. package/dist/correlation.d.ts +1 -4
  170. package/dist/correlation.js +7 -10
  171. package/dist/descriptors.d.ts +2 -12
  172. package/dist/descriptors.js +10 -6
  173. package/dist/frame-rpc.d.ts +9 -4
  174. package/dist/frame-rpc.js +19 -2
  175. package/dist/frame-stream.d.ts +33 -0
  176. package/dist/frame-stream.js +113 -0
  177. package/dist/generated/AcpLimitsConfig.d.ts +16 -0
  178. package/dist/generated/BindingLimitsConfig.d.ts +10 -0
  179. package/dist/generated/CreateVmConfig.d.ts +4 -0
  180. package/dist/generated/Http2LimitsConfig.d.ts +12 -0
  181. package/dist/generated/Http2LimitsConfig.js +2 -0
  182. package/dist/generated/JsRuntimeLimitsConfig.d.ts +1 -0
  183. package/dist/generated/MountPluginDescriptor.d.ts +1 -1
  184. package/dist/generated/ProcessLimitsConfig.d.ts +7 -0
  185. package/dist/generated/ProcessLimitsConfig.js +2 -0
  186. package/dist/generated/ReactorLimitsConfig.d.ts +23 -0
  187. package/dist/generated/ReactorLimitsConfig.js +2 -0
  188. package/dist/generated/SqliteLimitsConfig.d.ts +3 -0
  189. package/dist/generated/SqliteLimitsConfig.js +2 -0
  190. package/dist/generated/TlsLimitsConfig.d.ts +3 -0
  191. package/dist/generated/TlsLimitsConfig.js +2 -0
  192. package/dist/generated/UdpLimitsConfig.d.ts +4 -0
  193. package/dist/generated/UdpLimitsConfig.js +2 -0
  194. package/dist/generated/VmGroupConfig.d.ts +5 -0
  195. package/dist/generated/VmGroupConfig.js +2 -0
  196. package/dist/generated/VmLimitsConfig.d.ts +14 -2
  197. package/dist/generated/VmSqliteDescriptor.d.ts +10 -0
  198. package/dist/generated/VmSqliteDescriptor.js +2 -0
  199. package/dist/generated/VmUserAccountConfig.d.ts +9 -0
  200. package/dist/generated/VmUserAccountConfig.js +2 -0
  201. package/dist/generated/VmUserConfig.d.ts +19 -0
  202. package/dist/generated/VmUserConfig.js +1 -0
  203. package/dist/generated/WasmLimitsConfig.d.ts +1 -0
  204. package/dist/generated-protocol.d.ts +60 -2
  205. package/dist/generated-protocol.js +166 -31
  206. package/dist/kernel-proxy.d.ts +5 -1
  207. package/dist/kernel-proxy.js +82 -40
  208. package/dist/native-client.d.ts +9 -5
  209. package/dist/native-client.js +56 -11
  210. package/dist/node-runtime-options-schema.d.ts +1 -1
  211. package/dist/node-runtime-options-schema.js +43 -1
  212. package/dist/node-runtime.d.ts +12 -3
  213. package/dist/node-runtime.js +8 -7
  214. package/dist/process.d.ts +5 -1
  215. package/dist/process.js +35 -8
  216. package/dist/protocol-client.d.ts +28 -4
  217. package/dist/protocol-client.js +193 -12
  218. package/dist/protocol-frames.d.ts +14 -3
  219. package/dist/protocol-frames.js +26 -1
  220. package/dist/protocol-schema.d.ts +1 -1
  221. package/dist/protocol-schema.js +1 -1
  222. package/dist/request-payloads.d.ts +4 -1
  223. package/dist/request-payloads.js +7 -2
  224. package/dist/response-payloads.d.ts +23 -2
  225. package/dist/response-payloads.js +34 -2
  226. package/dist/sidecar-errors.d.ts +37 -0
  227. package/dist/sidecar-errors.js +27 -0
  228. package/dist/sidecar-process.d.ts +20 -6
  229. package/dist/sidecar-process.js +79 -15
  230. package/dist/state.d.ts +6 -6
  231. package/dist/state.js +10 -11
  232. package/dist/test-runtime.d.ts +24 -7
  233. package/dist/test-runtime.js +213 -67
  234. package/dist/vm-config.d.ts +5 -1
  235. package/package.json +11 -6
  236. package/commands/codex +0 -0
  237. package/commands/codex-exec +0 -0
  238. package/commands/http_get +0 -0
  239. package/dist/generated/ToolLimitsConfig.d.ts +0 -10
  240. /package/dist/generated/{ToolLimitsConfig.js → BindingLimitsConfig.js} +0 -0
package/dist/process.js CHANGED
@@ -1,13 +1,17 @@
1
- import { spawn, } from "node:child_process";
1
+ import { spawn } from "node:child_process";
2
2
  export { SidecarProcessError, SidecarProcessExited, } from "./sidecar-errors.js";
3
- import { SidecarProcessError, SidecarProcessExited, } from "./sidecar-errors.js";
3
+ import { SidecarProcessError, SidecarProcessExited } from "./sidecar-errors.js";
4
4
  export class StdioSidecarProcess {
5
5
  child;
6
+ control;
7
+ combinedStdio;
6
8
  stderrChunks = [];
7
9
  exitListeners = new Set();
8
10
  errorListeners = new Set();
9
- constructor(child) {
11
+ constructor(child, control) {
10
12
  this.child = child;
13
+ this.control = control;
14
+ this.combinedStdio = control === null;
11
15
  this.child.stderr.on("data", (chunk) => {
12
16
  this.stderrChunks.push(typeof chunk === "string" ? Buffer.from(chunk) : Buffer.from(chunk));
13
17
  });
@@ -30,13 +34,26 @@ export class StdioSidecarProcess {
30
34
  });
31
35
  }
32
36
  static spawn(options) {
33
- return new StdioSidecarProcess(spawn(options.command, options.args ?? [], {
37
+ const combinedStdio = options.combinedStdio === true;
38
+ const child = spawn(options.command, options.args ?? [], {
34
39
  cwd: options.cwd,
35
- stdio: ["pipe", "pipe", "pipe"],
36
- }));
40
+ env: combinedStdio
41
+ ? { ...process.env, AGENTOS_SIDECAR_COMBINED_STDIO: "1" }
42
+ : process.env,
43
+ stdio: combinedStdio
44
+ ? ["pipe", "pipe", "pipe"]
45
+ : ["pipe", "pipe", "pipe", "pipe"],
46
+ });
47
+ try {
48
+ return new StdioSidecarProcess(child, combinedStdio ? null : requireControlStream(child));
49
+ }
50
+ catch (error) {
51
+ child.kill("SIGKILL");
52
+ throw error;
53
+ }
37
54
  }
38
- static fromChild(child) {
39
- return new StdioSidecarProcess(child);
55
+ static fromChild(child, control) {
56
+ return new StdioSidecarProcess(child, control === null ? null : (control ?? requireControlStream(child)));
40
57
  }
41
58
  onExit(handler) {
42
59
  this.exitListeners.add(handler);
@@ -95,3 +112,13 @@ export class StdioSidecarProcess {
95
112
  });
96
113
  }
97
114
  }
115
+ function requireControlStream(child) {
116
+ const stream = child.stdio[3];
117
+ if (!stream ||
118
+ typeof stream.write !== "function" ||
119
+ typeof stream.on !== "function" ||
120
+ typeof stream.read !== "function") {
121
+ throw new Error("sidecar process did not expose a full-duplex fd 3");
122
+ }
123
+ return stream;
124
+ }
@@ -1,24 +1,38 @@
1
1
  import type { Readable, Writable } from "node:stream";
2
2
  import { type LiveSidecarEventSelector } from "./event-buffer.js";
3
- import type { FrameTransport } from "./frame-stream.js";
4
- import { type LiveEventFrame, type LiveProtocolFrame, type LiveResponseFrame, type LiveSidecarRequestFrame, type LiveSidecarRequestHandler, type ProtocolFramePayloadCodec } from "./protocol-frames.js";
3
+ import { type FrameTransport } from "./frame-stream.js";
5
4
  import type { LiveOwnershipScope } from "./ownership.js";
5
+ import { type LiveControlFrame, type LiveEventFrame, type LiveProtocolFrame, type LiveRequestFrame, type LiveResponseFrame, type LiveSidecarRequestFrame, type LiveSidecarRequestHandler, type LiveSidecarResponseFrame, type ProtocolFramePayloadCodec } from "./protocol-frames.js";
6
6
  import type { LiveRequestPayload } from "./request-payloads.js";
7
7
  export interface SidecarProtocolClientOptions {
8
+ /** A combined transport remains supported for embedders and focused tests. */
8
9
  frameTransport?: FrameTransport<LiveResponseFrame | LiveEventFrame | LiveSidecarRequestFrame, LiveProtocolFrame>;
10
+ ordinaryFrameTransport?: FrameTransport<LiveEventFrame, LiveRequestFrame>;
11
+ controlFrameTransport?: FrameTransport<LiveResponseFrame | LiveSidecarRequestFrame | LiveEventFrame, LiveSidecarResponseFrame | LiveControlFrame>;
9
12
  stdin?: Writable;
10
13
  stdout?: Readable;
11
- frameTimeoutMs: number;
14
+ control?: Readable & Writable;
15
+ /** Use one bidirectional stdin/stdout transport when the host cannot inherit fd 3. */
16
+ combinedStdio?: boolean;
12
17
  eventBufferCapacity: number;
13
18
  payloadCodec?: ProtocolFramePayloadCodec;
14
19
  stderrText?: () => string;
15
20
  frameError?: (error: Error) => Error;
16
21
  streamEndedError?: () => Error;
22
+ /** Override the silence watchdog window. Tests only; production uses the default. */
23
+ silenceTimeoutMs?: number;
24
+ /**
25
+ * Runs when the silence watchdog fires, before pending work is rejected.
26
+ * The stdio layer uses it to SIGKILL the sidecar child.
27
+ */
28
+ onSilenceExpired?: () => void;
17
29
  }
18
30
  export declare class SidecarProtocolClient {
19
31
  private readonly eventBuffer;
20
32
  private readonly eventListeners;
21
- private readonly frameTimeoutMs;
33
+ private readonly silenceTimeoutMs;
34
+ private silenceTimer;
35
+ private lastInboundAtMs;
22
36
  private readonly payloadCodec;
23
37
  private readonly stderrText;
24
38
  private readonly hostFrameFactory;
@@ -27,12 +41,22 @@ export declare class SidecarProtocolClient {
27
41
  private readonly eventWaiters;
28
42
  private sidecarRequestHandler;
29
43
  constructor(options: SidecarProtocolClientOptions);
44
+ /**
45
+ * Arm the silence watchdog: ANY inbound frame resets the clock (see the
46
+ * `onFrameActivity` tap above), and the sidecar heartbeats every 10s even
47
+ * while busy, so sustained silence for the full window means the process
48
+ * is dead or wedged — not slow. The check interval is unref'd so an idle
49
+ * host process can still exit naturally.
50
+ */
51
+ private startSilenceWatchdog;
52
+ private stopSilenceWatchdog;
30
53
  setSidecarRequestHandler(handler: LiveSidecarRequestHandler | null): void;
31
54
  onEvent(handler: (event: LiveEventFrame) => void): () => void;
32
55
  sendRequest(input: {
33
56
  ownership: LiveOwnershipScope;
34
57
  payload: LiveRequestPayload;
35
58
  }): Promise<LiveResponseFrame>;
59
+ shutdown(reason: string): Promise<void>;
36
60
  waitForEvent(matcher: LiveSidecarEventSelector | ((event: LiveEventFrame) => boolean), timeoutMs?: number, options?: {
37
61
  signal?: AbortSignal;
38
62
  }): Promise<LiveEventFrame>;
@@ -1,10 +1,22 @@
1
- import { SidecarEventBuffer, SidecarEventBufferOverflow, normalizeSidecarEventMatcher, sidecarEventWaitAbortError, } from "./event-buffer.js";
1
+ import { normalizeSidecarEventMatcher, SidecarEventBuffer, SidecarEventBufferOverflow, sidecarEventWaitAbortError, } from "./event-buffer.js";
2
2
  import { FrameRpcTransport } from "./frame-rpc.js";
3
- import { HostProtocolFrameFactory, classifySidecarWrittenProtocolFrame, decodeProtocolFramePayload, encodeProtocolFramePayload, resolveSidecarRequestFramePayload, } from "./protocol-frames.js";
3
+ import { SplitLaneFrameTransport, StdioFrameTransport, } from "./frame-stream.js";
4
+ import { classifySidecarWrittenProtocolFrame, decodeProtocolFramePayload, encodeProtocolFramePayload, HostProtocolFrameFactory, resolveSidecarRequestFramePayload, } from "./protocol-frames.js";
5
+ import { SidecarRejectedError, SidecarSilenceTimeout, } from "./sidecar-errors.js";
6
+ /**
7
+ * How long the host tolerates TOTAL inbound silence (no responses, events,
8
+ * sidecar requests, or heartbeats) before declaring the sidecar dead. The
9
+ * sidecar heartbeats every 10s from a dedicated thread, so this allows two
10
+ * missed beats plus margin; it bounds "sidecar is dead or wedged", never "this
11
+ * request is slow" — individual requests have no deadline of their own.
12
+ */
13
+ const DEFAULT_SIDECAR_SILENCE_TIMEOUT_MS = 30_000;
4
14
  export class SidecarProtocolClient {
5
15
  eventBuffer;
6
16
  eventListeners = new Set();
7
- frameTimeoutMs;
17
+ silenceTimeoutMs;
18
+ silenceTimer = null;
19
+ lastInboundAtMs = 0;
8
20
  payloadCodec;
9
21
  stderrText;
10
22
  hostFrameFactory = new HostProtocolFrameFactory();
@@ -13,14 +25,13 @@ export class SidecarProtocolClient {
13
25
  eventWaiters = new Set();
14
26
  sidecarRequestHandler = null;
15
27
  constructor(options) {
16
- this.frameTimeoutMs = options.frameTimeoutMs;
28
+ this.silenceTimeoutMs =
29
+ options.silenceTimeoutMs ?? DEFAULT_SIDECAR_SILENCE_TIMEOUT_MS;
17
30
  this.eventBuffer = new SidecarEventBuffer(options.eventBufferCapacity);
18
31
  this.payloadCodec = options.payloadCodec ?? "bare";
19
32
  this.stderrText = options.stderrText ?? (() => "");
20
33
  this.frameTransport = new FrameRpcTransport({
21
- frameTransport: options.frameTransport,
22
- stdin: options.stdin,
23
- stdout: options.stdout,
34
+ frameTransport: resolveProtocolFrameTransport(options, this.payloadCodec),
24
35
  encodeFrame: (frame) => encodeProtocolFramePayload(frame, this.payloadCodec),
25
36
  decodeFrame: (payload) => decodeProtocolFramePayload(payload, this.payloadCodec),
26
37
  classifyFrame: classifySidecarWrittenProtocolFrame,
@@ -38,6 +49,45 @@ export class SidecarProtocolClient {
38
49
  this.failPermanently(options.streamEndedError?.() ??
39
50
  new Error("sidecar protocol stream ended"));
40
51
  });
52
+ this.frameTransport.onFrameActivity(() => {
53
+ this.lastInboundAtMs = performance.now();
54
+ });
55
+ this.startSilenceWatchdog(options.onSilenceExpired);
56
+ }
57
+ /**
58
+ * Arm the silence watchdog: ANY inbound frame resets the clock (see the
59
+ * `onFrameActivity` tap above), and the sidecar heartbeats every 10s even
60
+ * while busy, so sustained silence for the full window means the process
61
+ * is dead or wedged — not slow. The check interval is unref'd so an idle
62
+ * host process can still exit naturally.
63
+ */
64
+ startSilenceWatchdog(onExpired) {
65
+ this.lastInboundAtMs = performance.now();
66
+ const checkIntervalMs = Math.max(Math.min(this.silenceTimeoutMs / 4, 1_000), 10);
67
+ this.silenceTimer = setInterval(() => {
68
+ const silenceMs = performance.now() - this.lastInboundAtMs;
69
+ if (silenceMs < this.silenceTimeoutMs) {
70
+ return;
71
+ }
72
+ this.stopSilenceWatchdog();
73
+ const error = new SidecarSilenceTimeout({
74
+ silenceMs,
75
+ stderr: this.stderrText(),
76
+ });
77
+ try {
78
+ onExpired?.();
79
+ }
80
+ finally {
81
+ this.failPermanently(error);
82
+ }
83
+ }, checkIntervalMs);
84
+ this.silenceTimer.unref?.();
85
+ }
86
+ stopSilenceWatchdog() {
87
+ if (this.silenceTimer !== null) {
88
+ clearInterval(this.silenceTimer);
89
+ this.silenceTimer = null;
90
+ }
41
91
  }
42
92
  setSidecarRequestHandler(handler) {
43
93
  this.sidecarRequestHandler = handler;
@@ -53,15 +103,21 @@ export class SidecarProtocolClient {
53
103
  throw this.closedError;
54
104
  }
55
105
  const request = this.hostFrameFactory.createRequestFrame(input);
56
- const response = await this.frameTransport.sendFrame(request.request_id, request, {
57
- timeoutMs: this.frameTimeoutMs,
58
- timeoutMessage: () => `timed out waiting for sidecar protocol frame for ${input.payload.type}\nstderr:\n${this.stderrText()}`,
59
- });
106
+ // No per-request deadline: only the caller knows whether an operation is
107
+ // legitimately long (a whole agent turn is one request). A dead or
108
+ // wedged sidecar rejects this via the silence watchdog instead.
109
+ const response = await this.frameTransport.sendFrame(request.request_id, request);
60
110
  if (response.payload.type === "rejected") {
61
- throw new Error(`sidecar rejected request ${request.request_id}: ${response.payload.code}: ${response.payload.message}`);
111
+ throw new SidecarRejectedError(request.request_id, response.payload);
62
112
  }
63
113
  return response;
64
114
  }
115
+ async shutdown(reason) {
116
+ if (this.closedError) {
117
+ throw this.closedError;
118
+ }
119
+ await this.frameTransport.writeFrame(this.hostFrameFactory.createControlFrame({ type: "shutdown", reason }));
120
+ }
65
121
  async waitForEvent(matcher, timeoutMs, options) {
66
122
  if (this.closedError instanceof SidecarEventBufferOverflow) {
67
123
  throw this.closedError;
@@ -126,15 +182,31 @@ export class SidecarProtocolClient {
126
182
  }
127
183
  }
128
184
  this.closedError = error;
185
+ this.stopSilenceWatchdog();
129
186
  this.rejectPending(error);
130
187
  }
131
188
  dispose() {
189
+ this.stopSilenceWatchdog();
132
190
  this.frameTransport.dispose();
133
191
  }
134
192
  async writeFrame(frame) {
135
193
  await this.frameTransport.writeFrame(frame);
136
194
  }
137
195
  async dispatchSidecarRequest(request) {
196
+ // A callback can arrive immediately before the response that acknowledges
197
+ // the command which created it. Let the inbound decoder finish that turn
198
+ // before writing a callback response; otherwise a very fast host callback
199
+ // can complete and reap the guest process while its execute request is
200
+ // still being admitted, leaving the host waiting for an exit it missed.
201
+ await new Promise((resolve) => {
202
+ const scheduleImmediate = globalThis.setImmediate;
203
+ if (scheduleImmediate) {
204
+ scheduleImmediate(resolve);
205
+ }
206
+ else {
207
+ setTimeout(resolve, 0);
208
+ }
209
+ });
138
210
  const payload = await resolveSidecarRequestFramePayload(request, this.sidecarRequestHandler);
139
211
  try {
140
212
  await this.writeFrame(this.hostFrameFactory.createSidecarResponseFrame({
@@ -148,6 +220,14 @@ export class SidecarProtocolClient {
148
220
  }
149
221
  }
150
222
  dispatchEvent(event) {
223
+ // Transport-level liveness beats from the sidecar. Their arrival already
224
+ // reset the silence watchdog at the frame layer; they carry no meaning
225
+ // for consumers and must never reach the bounded event buffer, where a
226
+ // long-idle VM would accumulate one every 10s until overflow.
227
+ if (event.payload.type === "structured" &&
228
+ event.payload.name === "heartbeat") {
229
+ return;
230
+ }
151
231
  for (const listener of this.eventListeners) {
152
232
  try {
153
233
  listener(event);
@@ -179,3 +259,104 @@ export class SidecarProtocolClient {
179
259
  this.eventWaiters.clear();
180
260
  }
181
261
  }
262
+ function resolveProtocolFrameTransport(options, payloadCodec) {
263
+ const hasSplitTransport = options.ordinaryFrameTransport !== undefined ||
264
+ options.controlFrameTransport !== undefined;
265
+ const hasStdio = options.stdin !== undefined ||
266
+ options.stdout !== undefined ||
267
+ options.control !== undefined;
268
+ if (options.combinedStdio) {
269
+ if (options.frameTransport ||
270
+ hasSplitTransport ||
271
+ options.control !== undefined ||
272
+ !options.stdin ||
273
+ !options.stdout) {
274
+ throw new Error("SidecarProtocolClient combinedStdio requires only stdin and stdout streams");
275
+ }
276
+ return new StdioFrameTransport({
277
+ stdin: options.stdin,
278
+ stdout: options.stdout,
279
+ encodeFrame: (frame) => encodeProtocolFramePayload(frame, payloadCodec),
280
+ decodeFrame: (payload) => decodeProtocolFramePayload(payload, payloadCodec),
281
+ });
282
+ }
283
+ if (options.frameTransport) {
284
+ if (hasSplitTransport || hasStdio) {
285
+ throw new Error("SidecarProtocolClient frameTransport cannot be combined with split-lane transports or streams");
286
+ }
287
+ return options.frameTransport;
288
+ }
289
+ let ordinary = options.ordinaryFrameTransport;
290
+ let control = options.controlFrameTransport;
291
+ if (hasSplitTransport) {
292
+ if (!ordinary || !control || hasStdio) {
293
+ throw new Error("SidecarProtocolClient requires both ordinaryFrameTransport and controlFrameTransport, without stdio streams");
294
+ }
295
+ }
296
+ else {
297
+ if (!options.stdin || !options.stdout || !options.control) {
298
+ throw new Error("SidecarProtocolClient requires a combined frameTransport or stdin/stdout/control streams");
299
+ }
300
+ ordinary = new StdioFrameTransport({
301
+ stdin: options.stdin,
302
+ stdout: options.stdout,
303
+ encodeFrame: (frame) => encodeProtocolFramePayload(frame, payloadCodec),
304
+ decodeFrame: (payload) => {
305
+ const frame = decodeProtocolFramePayload(payload, payloadCodec);
306
+ validateOrdinaryInboundFrame(frame);
307
+ return frame;
308
+ },
309
+ });
310
+ control = new StdioFrameTransport({
311
+ stdin: options.control,
312
+ stdout: options.control,
313
+ encodeFrame: (frame) => encodeProtocolFramePayload(frame, payloadCodec),
314
+ decodeFrame: (payload) => {
315
+ const frame = decodeProtocolFramePayload(payload, payloadCodec);
316
+ validateControlInboundFrame(frame);
317
+ return frame;
318
+ },
319
+ });
320
+ }
321
+ return new SplitLaneFrameTransport({
322
+ ordinary,
323
+ control,
324
+ validateOrdinaryFrame: validateOrdinaryInboundFrame,
325
+ validateControlFrame: validateControlInboundFrame,
326
+ selectWriteLane: (frame) => {
327
+ switch (frame.frame_type) {
328
+ case "request":
329
+ return "ordinary";
330
+ case "sidecar_response":
331
+ case "control":
332
+ return "control";
333
+ default: {
334
+ const invalidFrame = frame;
335
+ throw new Error(`host frame ${invalidFrame.frame_type} is not valid on either writable protocol lane`);
336
+ }
337
+ }
338
+ },
339
+ });
340
+ }
341
+ function validateOrdinaryInboundFrame(frame) {
342
+ if (frame.frame_type !== "event") {
343
+ throw new Error(`sidecar frame ${frame.frame_type} is not valid on the ordinary protocol lane`);
344
+ }
345
+ if (isHeartbeatFrame(frame)) {
346
+ throw new Error("sidecar heartbeat event is not valid on the ordinary protocol lane");
347
+ }
348
+ }
349
+ function validateControlInboundFrame(frame) {
350
+ if (frame.frame_type === "response" ||
351
+ frame.frame_type === "sidecar_request") {
352
+ return;
353
+ }
354
+ if (frame.frame_type === "event" &&
355
+ isHeartbeatFrame(frame)) {
356
+ return;
357
+ }
358
+ throw new Error(`sidecar frame ${frame.frame_type} is not valid on the control protocol lane`);
359
+ }
360
+ function isHeartbeatFrame(frame) {
361
+ return (frame.payload.type === "structured" && frame.payload.name === "heartbeat");
362
+ }
@@ -1,7 +1,7 @@
1
- import { type TransportPayloadCodec } from "./frame-payload-codec.js";
2
- import type { ClassifiedFrame } from "./frame-rpc.js";
3
1
  import { type LiveSidecarRequestPayload, type LiveSidecarResponsePayload } from "./callbacks.js";
4
2
  import { type LiveSidecarEventPayload } from "./event-buffer.js";
3
+ import { type TransportPayloadCodec } from "./frame-payload-codec.js";
4
+ import type { ClassifiedFrame } from "./frame-rpc.js";
5
5
  import * as protocol from "./generated-protocol.js";
6
6
  import { type LiveOwnershipScope } from "./ownership.js";
7
7
  import { SIDECAR_PROTOCOL_SCHEMA } from "./protocol-schema.js";
@@ -41,7 +41,16 @@ export interface LiveSidecarResponseFrame {
41
41
  ownership: LiveOwnershipScope;
42
42
  payload: LiveSidecarResponsePayload;
43
43
  }
44
- export type LiveProtocolFrame = LiveRequestFrame | LiveResponseFrame | LiveEventFrame | LiveSidecarRequestFrame | LiveSidecarResponseFrame;
44
+ export type LiveControlPayload = {
45
+ type: "shutdown";
46
+ reason: string;
47
+ };
48
+ export interface LiveControlFrame {
49
+ frame_type: "control";
50
+ schema: typeof SIDECAR_PROTOCOL_SCHEMA;
51
+ payload: LiveControlPayload;
52
+ }
53
+ export type LiveProtocolFrame = LiveRequestFrame | LiveResponseFrame | LiveEventFrame | LiveSidecarRequestFrame | LiveSidecarResponseFrame | LiveControlFrame;
45
54
  export type LiveSidecarWrittenProtocolFrame = LiveResponseFrame | LiveEventFrame | LiveSidecarRequestFrame;
46
55
  export type ProtocolFramePayloadCodec = TransportPayloadCodec;
47
56
  export type ClassifiedSidecarWrittenProtocolFrame = ClassifiedFrame<LiveResponseFrame, LiveEventFrame, LiveSidecarRequestFrame>;
@@ -56,6 +65,7 @@ export declare class HostProtocolFrameFactory {
56
65
  request: LiveSidecarRequestFrame;
57
66
  payload: LiveSidecarResponsePayload;
58
67
  }): LiveSidecarResponseFrame;
68
+ createControlFrame(payload: LiveControlPayload): LiveControlFrame;
59
69
  }
60
70
  export declare function resolveSidecarRequestFramePayload(request: LiveSidecarRequestFrame, handler: LiveSidecarRequestHandler | null): Promise<LiveSidecarResponsePayload>;
61
71
  export declare function toGeneratedProtocolFrame(frame: LiveProtocolFrame): protocol.ProtocolFrame;
@@ -65,4 +75,5 @@ export declare function encodeProtocolFramePayload(frame: LiveProtocolFrame, cod
65
75
  export declare function decodeProtocolFramePayload(payload: Uint8Array, codec: ProtocolFramePayloadCodec): LiveSidecarWrittenProtocolFrame;
66
76
  export declare function classifySidecarWrittenProtocolFrame(frame: LiveSidecarWrittenProtocolFrame): ClassifiedSidecarWrittenProtocolFrame;
67
77
  export declare function fromGeneratedSidecarWrittenProtocolFrame(frame: protocol.ProtocolFrame): LiveSidecarWrittenProtocolFrame;
78
+ export declare function toGeneratedControlPayload(payload: LiveControlPayload): protocol.ControlPayload;
68
79
  export declare function toLiveProtocolSchema(schema: protocol.ProtocolSchema): typeof SIDECAR_PROTOCOL_SCHEMA;
@@ -1,7 +1,7 @@
1
1
  import { toExactUint8Array } from "./bytes.js";
2
- import { decodeJsonFramePayload, encodeJsonFramePayload, } from "./frame-payload-codec.js";
3
2
  import { errorSidecarResponsePayload, fromGeneratedSidecarRequestPayload, isMatchingSidecarResponsePayload, toGeneratedSidecarResponsePayload, } from "./callbacks.js";
4
3
  import { fromGeneratedEventPayload, } from "./event-buffer.js";
4
+ import { decodeJsonFramePayload, encodeJsonFramePayload, } from "./frame-payload-codec.js";
5
5
  import * as protocol from "./generated-protocol.js";
6
6
  import { bigIntToSafeNumber } from "./numbers.js";
7
7
  import { fromGeneratedOwnershipScope, toGeneratedOwnershipScope, } from "./ownership.js";
@@ -28,6 +28,13 @@ export class HostProtocolFrameFactory {
28
28
  payload: input.payload,
29
29
  };
30
30
  }
31
+ createControlFrame(payload) {
32
+ return {
33
+ frame_type: "control",
34
+ schema: SIDECAR_PROTOCOL_SCHEMA,
35
+ payload,
36
+ };
37
+ }
31
38
  }
32
39
  export async function resolveSidecarRequestFramePayload(request, handler) {
33
40
  try {
@@ -66,6 +73,14 @@ export function toGeneratedProtocolFrame(frame) {
66
73
  payload: toGeneratedSidecarResponsePayload(frame.payload),
67
74
  },
68
75
  };
76
+ case "control":
77
+ return {
78
+ tag: "ControlFrame",
79
+ val: {
80
+ schema: frame.schema,
81
+ payload: toGeneratedControlPayload(frame.payload),
82
+ },
83
+ };
69
84
  case "response":
70
85
  case "event":
71
86
  case "sidecar_request":
@@ -131,9 +146,19 @@ export function fromGeneratedSidecarWrittenProtocolFrame(frame) {
131
146
  };
132
147
  case "RequestFrame":
133
148
  case "SidecarResponseFrame":
149
+ case "ControlFrame":
134
150
  throw new Error(`unsupported BARE protocol frame tag: ${frame.tag}`);
135
151
  }
136
152
  }
153
+ export function toGeneratedControlPayload(payload) {
154
+ switch (payload.type) {
155
+ case "shutdown":
156
+ return {
157
+ tag: "ShutdownControl",
158
+ val: { reason: payload.reason },
159
+ };
160
+ }
161
+ }
137
162
  export function toLiveProtocolSchema(schema) {
138
163
  return validateSidecarProtocolSchema(schema);
139
164
  }
@@ -1,6 +1,6 @@
1
1
  export declare const SIDECAR_PROTOCOL_SCHEMA: {
2
2
  readonly name: "agentos-native-sidecar";
3
- readonly version: 7;
3
+ readonly version: 8;
4
4
  };
5
5
  export type LiveProtocolSchema = typeof SIDECAR_PROTOCOL_SCHEMA;
6
6
  export type ProtocolSchemaLike = {
@@ -1,6 +1,6 @@
1
1
  export const SIDECAR_PROTOCOL_SCHEMA = {
2
2
  name: "agentos-native-sidecar",
3
- version: 7,
3
+ version: 8,
4
4
  };
5
5
  export function validateSidecarProtocolSchema(schema) {
6
6
  if (schema.name !== SIDECAR_PROTOCOL_SCHEMA.name ||
@@ -42,7 +42,7 @@ export type LiveRequestPayload = {
42
42
  packages?: LivePackageDescriptor[];
43
43
  packages_mount_at?: string;
44
44
  bootstrap_commands?: string[];
45
- tool_shim_commands?: string[];
45
+ binding_shim_commands?: string[];
46
46
  } | {
47
47
  type: "link_package";
48
48
  package: LivePackageDescriptor;
@@ -79,6 +79,9 @@ export type LiveRequestPayload = {
79
79
  lower_layer_ids: string[];
80
80
  } | {
81
81
  type: "snapshot_root_filesystem";
82
+ max_bytes: number;
83
+ } | {
84
+ type: "list_mounts";
82
85
  } | {
83
86
  type: "guest_kernel_call";
84
87
  execution_id: string;
@@ -58,7 +58,7 @@ export function toGeneratedRequestPayload(payload) {
58
58
  packages: (payload.packages ?? []).map(toGeneratedPackageDescriptor),
59
59
  packagesMountAt: payload.packages_mount_at ?? "",
60
60
  bootstrapCommands: payload.bootstrap_commands ?? [],
61
- toolShimCommands: payload.tool_shim_commands ?? [],
61
+ bindingShimCommands: payload.binding_shim_commands ?? [],
62
62
  },
63
63
  };
64
64
  case "link_package":
@@ -153,7 +153,12 @@ export function toGeneratedRequestPayload(payload) {
153
153
  },
154
154
  };
155
155
  case "snapshot_root_filesystem":
156
- return { tag: "SnapshotRootFilesystemRequest", val: null };
156
+ return {
157
+ tag: "SnapshotRootFilesystemRequest",
158
+ val: { maxBytes: BigInt(payload.max_bytes) },
159
+ };
160
+ case "list_mounts":
161
+ return { tag: "ListMountsRequest", val: null };
157
162
  case "execute":
158
163
  return {
159
164
  tag: "ExecuteRequest",
@@ -1,5 +1,5 @@
1
- import { type LiveRootFilesystemEntry, type LiveRootFilesystemEntryEncoding } from "./filesystem.js";
2
1
  import { type LiveExtEnvelope } from "./ext.js";
2
+ import { type LiveRootFilesystemEntry, type LiveRootFilesystemEntryEncoding } from "./filesystem.js";
3
3
  import type * as protocol from "./generated-protocol.js";
4
4
  import { type LiveFilesystemOperation, type LiveGuestFilesystemOperation, type LiveSignalDispositionAction } from "./protocol-maps.js";
5
5
  import { type LiveGuestFilesystemStat, type LiveProcessSnapshotEntry, type LiveSocketStateEntry } from "./state.js";
@@ -9,7 +9,7 @@ export interface LiveGuestDirEntry {
9
9
  path: string;
10
10
  isDirectory: boolean;
11
11
  isSymbolicLink: boolean;
12
- size: number;
12
+ size: bigint;
13
13
  }
14
14
  export interface LiveSignalHandlerRegistration {
15
15
  action: LiveSignalDispositionAction;
@@ -49,6 +49,11 @@ export interface LivePackageCommands {
49
49
  package_name: string;
50
50
  commands: string[];
51
51
  }
52
+ export interface LiveMountInfo {
53
+ path: string;
54
+ kind: string;
55
+ read_only: boolean;
56
+ }
52
57
  export interface LiveAgentosProjectedAgent {
53
58
  id: string;
54
59
  acp_entrypoint: string;
@@ -79,6 +84,9 @@ export type LiveResponsePayload = {
79
84
  } | {
80
85
  type: "provided_commands_response";
81
86
  packages: LivePackageCommands[];
87
+ } | {
88
+ type: "mounts_listed";
89
+ mounts: LiveMountInfo[];
82
90
  } | {
83
91
  type: "host_callbacks_registered";
84
92
  registration: string;
@@ -179,6 +187,19 @@ export type LiveResponsePayload = {
179
187
  type: "rejected";
180
188
  code: string;
181
189
  message: string;
190
+ limit_name: string | null;
191
+ configured_limit: number | null;
192
+ current_usage: number | null;
193
+ requested: number | null;
194
+ unit: string | null;
195
+ scope: string | null;
196
+ vm_id: string | null;
197
+ session_generation: number | null;
198
+ capability_id: number | null;
199
+ operation: string | null;
200
+ configuration_path: string | null;
201
+ retryable: boolean | null;
202
+ errno: string | null;
182
203
  } | {
183
204
  type: "ext_result";
184
205
  envelope: LiveExtEnvelope;