@rynx-ai/server 0.1.9 → 0.1.10-beta.3

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 (39) hide show
  1. package/dist/browser-surface-ws.d.ts +2 -0
  2. package/dist/browser-surface-ws.js +1 -0
  3. package/dist/control-api.d.ts +17 -0
  4. package/dist/control-api.js +809 -9
  5. package/dist/control-web/assets/{highlighted-body-OFNGDK62-e-w61YLy.js → highlighted-body-OFNGDK62-D-FhYROw.js} +1 -1
  6. package/dist/control-web/assets/index-BKzSsGxH.js +671 -0
  7. package/dist/control-web/assets/index-DykWY_Vk.css +32 -0
  8. package/dist/control-web/assets/{mermaid-GHXKKRXX-DZn7Hbr2.js → mermaid-GHXKKRXX-DE-Ovg9T.js} +3 -3
  9. package/dist/control-web/index.html +2 -2
  10. package/dist/desktop-browser-host.d.ts +20 -3
  11. package/dist/desktop-browser-host.js +126 -44
  12. package/dist/direct-runtime-browser-inspect-server.d.ts +72 -0
  13. package/dist/direct-runtime-browser-inspect-server.js +749 -0
  14. package/dist/direct-runtime-server.d.ts +6 -0
  15. package/dist/direct-runtime-server.js +29 -1
  16. package/dist/emulator-surface-ws.d.ts +2 -0
  17. package/dist/emulator-surface-ws.js +1 -0
  18. package/dist/machine-session-service.d.ts +88 -5
  19. package/dist/machine-session-service.js +283 -20
  20. package/dist/remote-runtime-dispatcher.d.ts +1 -1
  21. package/dist/remote-runtime-dispatcher.js +25 -2
  22. package/dist/remote-runtime-session-projection.js +10 -0
  23. package/dist/runtime-web-auth.d.ts +5 -0
  24. package/dist/runtime-web-auth.js +43 -3
  25. package/dist/server.d.ts +78 -8
  26. package/dist/server.js +42 -17
  27. package/dist/session-browser-service.d.ts +30 -0
  28. package/dist/session-browser-service.js +89 -3
  29. package/dist/session-browser-surface-coordinator.d.ts +4 -3
  30. package/dist/session-browser-surface-coordinator.js +374 -268
  31. package/dist/session-runtime-index.d.ts +6 -0
  32. package/dist/session-runtime-index.js +10 -0
  33. package/dist/session-terminal-host.d.ts +6 -1
  34. package/dist/session-terminal-host.js +18 -0
  35. package/dist/terminal-ws.d.ts +3 -0
  36. package/dist/terminal-ws.js +1 -0
  37. package/package.json +12 -7
  38. package/dist/control-web/assets/index-BQ7XVBKO.css +0 -32
  39. package/dist/control-web/assets/index-ClpzuBJx.js +0 -606
@@ -4,6 +4,7 @@ import { type RuntimeEmulatorSurfaceClientFrame, type RuntimeEmulatorSurfaceOpen
4
4
  import { WebSocket } from "ws";
5
5
  import { type AuthenticatedRuntimeSubject, type RemoteRuntimeDispatcher } from "./remote-runtime-dispatcher.js";
6
6
  import { type DirectRuntimeBrowserSurfaceHost, type DirectRuntimeBrowserSurfaceServerLimits } from "./direct-runtime-browser-surface-server.js";
7
+ import { type DirectRuntimeBrowserInspectHost, type DirectRuntimeBrowserInspectServerLimits } from "./direct-runtime-browser-inspect-server.js";
7
8
  export { DIRECT_RUNTIME_CONTROL_PATH };
8
9
  export interface DirectRuntimeAuthenticator {
9
10
  createServerHello(input: {
@@ -87,6 +88,11 @@ export interface StartDirectRuntimeServerOptions {
87
88
  host: DirectRuntimeBrowserSurfaceHost;
88
89
  limits?: Partial<Pick<DirectRuntimeBrowserSurfaceServerLimits, "maxQueuedFrames" | "maxBufferedBytes" | "peerLivenessTimeoutMs">>;
89
90
  };
91
+ /** Optional dedicated V4 transparent Browser Inspect transport. */
92
+ browserInspect?: {
93
+ host: DirectRuntimeBrowserInspectHost;
94
+ limits?: Partial<Pick<DirectRuntimeBrowserInspectServerLimits, "maxQueuedBytes" | "maxBufferedBytes" | "peerLivenessTimeoutMs">>;
95
+ };
90
96
  /** Session-owned Emulator frames on a dedicated authenticated control connection. */
91
97
  emulatorSurface?: {
92
98
  host: DirectRuntimeEmulatorSurfaceHost;
@@ -1,10 +1,11 @@
1
1
  import { createServer, } from "node:http";
2
- import { decodeDirectRuntimeFrame, DIRECT_RUNTIME_CLOSE_CODE, DIRECT_RUNTIME_BROWSER_SURFACE_PATH, DIRECT_RUNTIME_CONTROL_PATH, DIRECT_RUNTIME_MAX_HANDSHAKE_FRAME_BYTES, encodeDirectRuntimeFrame, parseServerAccepted, parseServerHello, } from "@rynx-ai/protocol/direct-runtime";
2
+ import { decodeDirectRuntimeFrame, DIRECT_RUNTIME_CLOSE_CODE, DIRECT_RUNTIME_BROWSER_INSPECT_PATH, DIRECT_RUNTIME_BROWSER_SURFACE_PATH, DIRECT_RUNTIME_CONTROL_PATH, DIRECT_RUNTIME_MAX_HANDSHAKE_FRAME_BYTES, encodeDirectRuntimeFrame, parseServerAccepted, parseServerHello, } from "@rynx-ai/protocol/direct-runtime";
3
3
  import { createServerE2EEChannel, DIRECT_RUNTIME_E2EE_MAX_ENVELOPE_BYTES, } from "@rynx-ai/remote-runtime-e2ee";
4
4
  import { encodeRemoteRuntimeSessionEventsFrame, encodeRemoteRuntimeSessionTerminalServerFrame, encodeRemoteRuntimeRpcResponse, parseRemoteRuntimeRpcFrame, parseRemoteRuntimeSessionEventsFrame, parseRemoteRuntimeSessionTerminalClientFrame, REMOTE_RUNTIME_SESSION_TERMINAL_MAX_DATA_BYTES, REMOTE_RUNTIME_RPC_MAX_FRAME_BYTES, REMOTE_RUNTIME_RPC_MAX_ID_CHARS, REMOTE_RUNTIME_RPC_METHOD_METADATA, } from "@rynx-ai/protocol/remote-runtime-rpc";
5
5
  import { encodeRuntimeEmulatorSurfaceServerFrame, parseRuntimeEmulatorSurfaceClientFrame, RUNTIME_EMULATOR_SURFACE_CHUNK_BYTES, RUNTIME_EMULATOR_SURFACE_MAX_FRAME_BYTES, } from "@rynx-ai/protocol/runtime-emulator-surface";
6
6
  import { WebSocket, WebSocketServer } from "ws";
7
7
  import { attachDirectRuntimeBrowserSurfaceServer, } from "./direct-runtime-browser-surface-server.js";
8
+ import { attachDirectRuntimeBrowserInspectServer, } from "./direct-runtime-browser-inspect-server.js";
8
9
  export { DIRECT_RUNTIME_CONTROL_PATH };
9
10
  const CLOSE_BAD_PROTOCOL = DIRECT_RUNTIME_CLOSE_CODE.badProtocol;
10
11
  const CLOSE_UNAUTHORIZED = DIRECT_RUNTIME_CLOSE_CODE.unauthorized;
@@ -149,6 +150,28 @@ export async function startDirectRuntimeServer(options) {
149
150
  onError: options.onError,
150
151
  })
151
152
  : undefined;
153
+ const browserInspectServer = options.browserInspect
154
+ ? attachDirectRuntimeBrowserInspectServer(server, {
155
+ e2ee: options.e2ee,
156
+ authenticator: options.authenticator,
157
+ host: options.browserInspect.host,
158
+ isPeerActive: options.isPeerActive,
159
+ connectionHub,
160
+ limits: {
161
+ ...options.browserInspect.limits,
162
+ authenticationTimeoutMs: limits.authenticationTimeoutMs,
163
+ maxConnections: limits.maxConnections,
164
+ maxUnauthenticatedConnectionsPerSource: limits.maxUnauthenticatedConnectionsPerSource,
165
+ maxAuthenticationAttemptsPerSource: limits.maxAuthenticationAttemptsPerSource,
166
+ authenticationAttemptWindowMs: limits.authenticationAttemptWindowMs,
167
+ maxTrackedAuthenticationSources: limits.maxTrackedAuthenticationSources,
168
+ maxConnectionsPerGrant: limits.maxConnectionsPerGrant,
169
+ heartbeatIntervalMs: limits.heartbeatIntervalMs,
170
+ shutdownDeadlineMs: limits.shutdownDeadlineMs,
171
+ },
172
+ onError: options.onError,
173
+ })
174
+ : undefined;
152
175
  server.on("upgrade", (request, socket, head) => {
153
176
  const sourceAddress = socketSourceAddress(request);
154
177
  if (stopping) {
@@ -158,6 +181,9 @@ export async function startDirectRuntimeServer(options) {
158
181
  if (browserSurfaceServer && request.url === DIRECT_RUNTIME_BROWSER_SURFACE_PATH) {
159
182
  return;
160
183
  }
184
+ if (browserInspectServer && request.url === DIRECT_RUNTIME_BROWSER_INSPECT_PATH) {
185
+ return;
186
+ }
161
187
  if (request.url !== DIRECT_RUNTIME_CONTROL_PATH) {
162
188
  rejectUpgrade(socket, 404, "Direct Runtime route not found");
163
189
  return;
@@ -1468,6 +1494,7 @@ export async function startDirectRuntimeServer(options) {
1468
1494
  }
1469
1495
  const deadline = Date.now() + limits.shutdownDeadlineMs;
1470
1496
  const browserSurfaceClosed = browserSurfaceServer?.shutdown() ?? Promise.resolve();
1497
+ const browserInspectClosed = browserInspectServer?.shutdown() ?? Promise.resolve();
1471
1498
  const httpClosed = closeHttpServer(server);
1472
1499
  const shutdownReason = new Error("Direct Runtime server is shutting down");
1473
1500
  for (const controller of activeDispatchControllers)
@@ -1481,6 +1508,7 @@ export async function startDirectRuntimeServer(options) {
1481
1508
  const drained = Promise.all([
1482
1509
  httpClosed,
1483
1510
  browserSurfaceClosed,
1511
+ browserInspectClosed,
1484
1512
  waitForConnectionsEmpty(allConnections, emptyWaiters),
1485
1513
  Promise.allSettled([...activeDispatches]),
1486
1514
  ]);
@@ -1,6 +1,8 @@
1
1
  import type { Server } from "node:http";
2
2
  import { WebSocketServer } from "ws";
3
+ import { type RuntimeWebAccessPolicy } from "./runtime-web-auth.js";
3
4
  import type { RuntimeConnectionResolverHost } from "./server.js";
4
5
  export declare function attachEmulatorSurfaceWs(server: Server, deps: {
5
6
  runtimeConnectionResolver?: RuntimeConnectionResolverHost;
7
+ runtimeWebAccess?: RuntimeWebAccessPolicy;
6
8
  }): WebSocketServer;
@@ -19,6 +19,7 @@ export function attachEmulatorSurfaceWs(server, deps) {
19
19
  const authorization = authorizeRuntimeWebRequest(request, {
20
20
  mutation: true,
21
21
  capability: parsed.url.searchParams.get(RUNTIME_WEB_CAPABILITY_QUERY) ?? "",
22
+ access: deps.runtimeWebAccess,
22
23
  });
23
24
  if (authorization)
24
25
  return rejectUpgrade(socket, authorization.status, authorization.error);
@@ -7,8 +7,9 @@
7
7
  * Direct adapters can therefore expose the same behavior without copying state
8
8
  * into a Control Plane database.
9
9
  */
10
- import { type AgentRuntimeId, type AgentSpec, type ConversationRuntime, type SessionProviderId, type ReasoningEffort, type SessionBus, type SessionLogStore, type SessionRegistry } from "@rynx-ai/core";
11
- import type { SequencedSessionEvent, SessionInteractionResolution, SessionItem } from "@rynx-ai/protocol";
10
+ import { type AgentRuntimeId, type AgentSpec, type ConversationRuntime, type SessionProviderId, type ReasoningEffort, type RuntimeUserInput, type SessionBus, type SessionLogStore, type SessionRegistry } from "@rynx-ai/core";
11
+ import type { SequencedSessionEvent, SessionInteractionResolution, SessionItem, UserContentPart } from "@rynx-ai/protocol";
12
+ import type { RemoteRuntimeSessionResourceDeleteParams, RemoteRuntimeSessionResourceDeleteResult, RemoteRuntimeSessionResourceGetParams, RemoteRuntimeSessionResourceGetResult, RemoteRuntimeSessionResourcePolicyResult, RemoteRuntimeSessionResourceReadParams, RemoteRuntimeSessionResourceReadResult, RemoteRuntimeSessionResourceUploadBeginParams, RemoteRuntimeSessionResourceUploadBeginResult, RemoteRuntimeSessionResourceUploadChunkParams, RemoteRuntimeSessionResourceUploadChunkResult, RemoteRuntimeSessionResourceUploadCommitParams, RemoteRuntimeSessionResourceUploadCommitResult } from "@rynx-ai/protocol/remote-runtime-rpc";
12
13
  import type { ControlAgentSummary, ControlSessionInteractionResolveDisposition, ControlSessionRuntimeSnapshot } from "@rynx-ai/protocol/control";
13
14
  import { type RemoteRuntimeSessionInterruptResult, type RemoteRuntimeSessionLaunchOptionsListResult, type RemoteRuntimeSessionListParams, type RemoteRuntimeSessionListResult, type RemoteRuntimeSessionSnapshotParams } from "@rynx-ai/protocol/remote-runtime-rpc";
14
15
  import { type CodexRuntimeStatus, type CodexSessionStore, type InjectOutcome } from "@rynx-ai/runtime";
@@ -22,6 +23,44 @@ export interface MachineSessionInterruptPort {
22
23
  export interface MachineSessionAgentCatalogPort {
23
24
  list(): Promise<ControlAgentSummary[]>;
24
25
  }
26
+ export interface MachineSessionPendingMessage {
27
+ sessionId: string;
28
+ message: string;
29
+ createdAt: string;
30
+ state: "queued" | "outcome_unknown";
31
+ }
32
+ /** Durable one-message admission queue used while a Provider needs setup. */
33
+ export interface MachineSessionPendingMessagePort {
34
+ put(message: Omit<MachineSessionPendingMessage, "state">): boolean | Promise<boolean>;
35
+ get(sessionId: string): MachineSessionPendingMessage | undefined | Promise<MachineSessionPendingMessage | undefined>;
36
+ list(): MachineSessionPendingMessage[] | Promise<MachineSessionPendingMessage[]>;
37
+ markOutcomeUnknown(sessionId: string): void | Promise<void>;
38
+ delete(sessionId: string): void | Promise<void>;
39
+ }
40
+ export type MachineSessionMessageOperationState = "prepared" | "injecting" | "injected" | "mirrored" | "outcome_unknown" | "failed_not_started";
41
+ export interface MachineSessionPreparedInput {
42
+ input: RuntimeUserInput;
43
+ title: string;
44
+ operationState?: MachineSessionMessageOperationState;
45
+ }
46
+ /** Target-daemon resource authority. Transfer methods are deliberately chunked
47
+ * below the 64 KiB Direct Runtime frame; `prepareInput` is the only method that
48
+ * can turn opaque browser-visible ids into runtime-local file paths. */
49
+ export interface MachineSessionResourcePort {
50
+ policy(sessionId: string): RemoteRuntimeSessionResourcePolicyResult;
51
+ beginUpload(input: RemoteRuntimeSessionResourceUploadBeginParams): Promise<RemoteRuntimeSessionResourceUploadBeginResult>;
52
+ writeUploadChunk(input: RemoteRuntimeSessionResourceUploadChunkParams): Promise<RemoteRuntimeSessionResourceUploadChunkResult>;
53
+ commitUpload(input: RemoteRuntimeSessionResourceUploadCommitParams): Promise<RemoteRuntimeSessionResourceUploadCommitResult>;
54
+ getResource(input: RemoteRuntimeSessionResourceGetParams): Promise<RemoteRuntimeSessionResourceGetResult>;
55
+ readResource(input: RemoteRuntimeSessionResourceReadParams): Promise<RemoteRuntimeSessionResourceReadResult>;
56
+ deleteResource(input: RemoteRuntimeSessionResourceDeleteParams): Promise<RemoteRuntimeSessionResourceDeleteResult>;
57
+ prepareInput(sessionId: string, content: UserContentPart[], clientMessageId?: string): Promise<MachineSessionPreparedInput>;
58
+ markMessageInjecting(sessionId: string, clientMessageId: string): void | Promise<void>;
59
+ markMessageInjected(sessionId: string, clientMessageId: string): void | Promise<void>;
60
+ markMessageOutcomeUnknown(sessionId: string, clientMessageId: string, reason: string): void | Promise<void>;
61
+ markMessageFailedNotStarted(sessionId: string, clientMessageId: string, reason: string): void | Promise<void>;
62
+ deleteSession(sessionId: string): void | Promise<void>;
63
+ }
25
64
  export interface MachineSessionRunnerPort {
26
65
  ensureLiveSession(sessionId: string, options?: {
27
66
  cwd?: string;
@@ -32,8 +71,18 @@ export interface MachineSessionRunnerPort {
32
71
  agentName?: string;
33
72
  agentSpec?: AgentSpec;
34
73
  }): Promise<boolean>;
74
+ /** Start the Provider TUI pane without waiting for its native thread to bind. */
75
+ startLiveSession?(sessionId: string, options?: {
76
+ cwd?: string;
77
+ cols?: number;
78
+ rows?: number;
79
+ runtime?: AgentRuntimeId;
80
+ reasoningEffort?: ReasoningEffort;
81
+ agentName?: string;
82
+ agentSpec?: AgentSpec;
83
+ }): Promise<boolean>;
35
84
  lastLiveSessionError?(sessionId: string): string | undefined;
36
- injectMessage(sessionId: string, text: string): Promise<InjectOutcome>;
85
+ injectMessage(sessionId: string, input: RuntimeUserInput | string): Promise<InjectOutcome>;
37
86
  stopRunner(sessionId: string): void;
38
87
  resolveInteraction(sessionId: string, interactionId: string, resolution: SessionInteractionResolution): Promise<{
39
88
  disposition: ControlSessionInteractionResolveDisposition;
@@ -56,6 +105,9 @@ export interface MachineSessionServicePorts {
56
105
  };
57
106
  /** Target-daemon catalog. Exposed only as bounded Session creation options. */
58
107
  agents?: MachineSessionAgentCatalogPort;
108
+ /** Durable first messages that must not reach a Provider setup prompt. */
109
+ pendingMessages?: MachineSessionPendingMessagePort;
110
+ resources?: MachineSessionResourcePort;
59
111
  /** Native Session execution belongs to the target daemon, never the caller. */
60
112
  execution?: {
61
113
  runtime: Pick<ConversationRuntime, "resolveRuntime">;
@@ -74,6 +126,8 @@ export interface MachineSessionServiceOptions {
74
126
  snapshotPageMaxBytes?: number;
75
127
  /** Bound for the current registry/log merge until storage offers keyset paging. */
76
128
  directoryScanLimit?: number;
129
+ /** Delay between setup-readiness retries for durable pending messages. */
130
+ pendingMessageRetryMs?: number;
77
131
  }
78
132
  export type MachineSessionListInput = RemoteRuntimeSessionListParams;
79
133
  export interface MachineSessionListPage extends RemoteRuntimeSessionListResult {
@@ -109,6 +163,15 @@ export interface MachineSessionMessageResult {
109
163
  ok: true;
110
164
  injected: true;
111
165
  }
166
+ export interface MachineSessionMessageInput {
167
+ message?: string;
168
+ content?: UserContentPart[];
169
+ clientMessageId?: string;
170
+ }
171
+ export interface MachineSessionMessageEnqueueResult {
172
+ ok: true;
173
+ queued: true;
174
+ }
112
175
  export interface MachineSessionTerminalStartResult {
113
176
  ok: true;
114
177
  }
@@ -130,7 +193,7 @@ export interface MachineSessionWatch extends AsyncIterable<SequencedSessionEvent
130
193
  export declare class MachineSessionServiceInputError extends Error {
131
194
  constructor(message: string);
132
195
  }
133
- export type MachineSessionServiceFailureCode = "not_found" | "failed_precondition" | "outcome_unknown";
196
+ export type MachineSessionServiceFailureCode = "not_found" | "failed_precondition" | "conflict" | "outcome_unknown";
134
197
  /** Expected application failure; adapters decide how to represent it on the wire. */
135
198
  export declare class MachineSessionServiceFailure extends Error {
136
199
  readonly code: MachineSessionServiceFailureCode;
@@ -145,6 +208,9 @@ export declare class MachineSessionService {
145
208
  private readonly maxSnapshotItemLimit;
146
209
  private readonly snapshotPageMaxBytes;
147
210
  private readonly directoryScanLimit;
211
+ private readonly pendingMessageRetryMs;
212
+ private readonly pendingDeliveries;
213
+ private readonly cancelledPendingDeliveries;
148
214
  constructor(ports: MachineSessionServicePorts, options?: MachineSessionServiceOptions);
149
215
  list(input?: MachineSessionListInput): Promise<MachineSessionListPage>;
150
216
  snapshot(input: MachineSessionSnapshotInput): Promise<MachineSessionSnapshotPage>;
@@ -166,13 +232,30 @@ export declare class MachineSessionService {
166
232
  /** Create target-owned Session identity from one Agent preset or direct Provider. */
167
233
  create(input: MachineSessionCreateInput): Promise<MachineSessionCreateResult>;
168
234
  /** Inject one turn through the target daemon's native single-writer runner. */
169
- sendMessage(sessionIdInput: string, messageInput: string): Promise<MachineSessionMessageResult>;
235
+ sendMessage(sessionIdInput: string, messageInput: string | MachineSessionMessageInput): Promise<MachineSessionMessageResult>;
236
+ resourcePolicy(sessionIdInput: string): RemoteRuntimeSessionResourcePolicyResult;
237
+ beginResourceUpload(input: RemoteRuntimeSessionResourceUploadBeginParams): Promise<RemoteRuntimeSessionResourceUploadBeginResult>;
238
+ writeResourceUploadChunk(input: RemoteRuntimeSessionResourceUploadChunkParams): Promise<RemoteRuntimeSessionResourceUploadChunkResult>;
239
+ commitResourceUpload(input: RemoteRuntimeSessionResourceUploadCommitParams): Promise<RemoteRuntimeSessionResourceUploadCommitResult>;
240
+ getResource(input: RemoteRuntimeSessionResourceGetParams): Promise<RemoteRuntimeSessionResourceGetResult>;
241
+ readResource(input: RemoteRuntimeSessionResourceReadParams): Promise<RemoteRuntimeSessionResourceReadResult>;
242
+ deleteResource(input: RemoteRuntimeSessionResourceDeleteParams): Promise<RemoteRuntimeSessionResourceDeleteResult>;
243
+ /** Persist the first task while login/onboarding owns the Provider TUI. The
244
+ * delivery worker starts the pane now, waits for a real native thread, then
245
+ * injects exactly once. `failed` is fenced as outcome_unknown and never retried. */
246
+ enqueueMessage(sessionIdInput: string, messageInput: string): Promise<MachineSessionMessageEnqueueResult>;
170
247
  /** Explicitly restore the target daemon's live runner without starting a turn. */
171
248
  startTerminal(sessionIdInput: string): Promise<MachineSessionTerminalStartResult>;
172
249
  private ensureLiveSession;
250
+ private liveSessionRequest;
173
251
  resolveInteraction(sessionIdInput: string, interactionIdInput: string, resolution: SessionInteractionResolution): Promise<MachineSessionInteractionResult>;
174
252
  delete(sessionIdInput: string): Promise<MachineSessionDeleteResult>;
175
253
  private requireAgents;
254
+ private requireResources;
255
+ private requireResourceSession;
256
+ private resumePendingDeliveries;
257
+ private schedulePendingDelivery;
258
+ private deliverPendingMessage;
176
259
  private runtimeReadiness;
177
260
  private probeRuntimeReadiness;
178
261
  private requireExecution;