cleanup: small optimizations
This commit is contained in:
@@ -129,7 +129,7 @@ export async function handleIpcRequest(request: OrchestratorRequest): Promise<Or
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function attachIpcInstance(
|
export function openRpcStream(
|
||||||
instanceId: string,
|
instanceId: string,
|
||||||
onResponse: (response: RpcResponse) => void,
|
onResponse: (response: RpcResponse) => void,
|
||||||
onSessionEvent: (event: AgentSessionEvent) => void,
|
onSessionEvent: (event: AgentSessionEvent) => void,
|
||||||
@@ -140,7 +140,7 @@ export function attachIpcInstance(
|
|||||||
close(): void;
|
close(): void;
|
||||||
}
|
}
|
||||||
| undefined {
|
| undefined {
|
||||||
const handle = supervisor.attachInstance(instanceId, onSessionEvent, onUiRequest);
|
const handle = supervisor.openRpcStream(instanceId, onSessionEvent, onUiRequest);
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export interface IpcRequestHandler {
|
|||||||
(request: RpcRequest): Promise<RpcBridgeResponse | ErrorResponse> | RpcBridgeResponse | ErrorResponse;
|
(request: RpcRequest): Promise<RpcBridgeResponse | ErrorResponse> | RpcBridgeResponse | ErrorResponse;
|
||||||
(request: RpcStreamRequest): Promise<RpcReadyResponse | ErrorResponse> | RpcReadyResponse | ErrorResponse;
|
(request: RpcStreamRequest): Promise<RpcReadyResponse | ErrorResponse> | RpcReadyResponse | ErrorResponse;
|
||||||
(request: OrchestratorRequest): Promise<OrchestratorResponse> | OrchestratorResponse;
|
(request: OrchestratorRequest): Promise<OrchestratorResponse> | OrchestratorResponse;
|
||||||
attach(
|
openRpcStream(
|
||||||
instanceId: string,
|
instanceId: string,
|
||||||
onResponse: (response: import("@earendil-works/pi-coding-agent").RpcResponse) => void,
|
onResponse: (response: import("@earendil-works/pi-coding-agent").RpcResponse) => void,
|
||||||
onSessionEvent: (event: import("@earendil-works/pi-coding-agent").AgentSessionEvent) => void,
|
onSessionEvent: (event: import("@earendil-works/pi-coding-agent").AgentSessionEvent) => void,
|
||||||
@@ -72,7 +72,7 @@ export async function startIpcServer(handler: IpcRequestHandler): Promise<Server
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const attachment = handler.attach(
|
const rpcStream = handler.openRpcStream(
|
||||||
request.instanceId,
|
request.instanceId,
|
||||||
(response) => {
|
(response) => {
|
||||||
socket.write(encodeMessage(response));
|
socket.write(encodeMessage(response));
|
||||||
@@ -84,7 +84,7 @@ export async function startIpcServer(handler: IpcRequestHandler): Promise<Server
|
|||||||
socket.write(encodeMessage(request));
|
socket.write(encodeMessage(request));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (!attachment) {
|
if (!rpcStream) {
|
||||||
socket.end(
|
socket.end(
|
||||||
encodeMessage({ type: "error", ok: false, error: `Unknown instance: ${request.instanceId}` }),
|
encodeMessage({ type: "error", ok: false, error: `Unknown instance: ${request.instanceId}` }),
|
||||||
);
|
);
|
||||||
@@ -108,7 +108,7 @@ export async function startIpcServer(handler: IpcRequestHandler): Promise<Server
|
|||||||
void (async () => {
|
void (async () => {
|
||||||
try {
|
try {
|
||||||
const rpcRequest = JSON.parse(rpcLine) as RpcClientMessage;
|
const rpcRequest = JSON.parse(rpcLine) as RpcClientMessage;
|
||||||
await attachment.handleRequest(rpcRequest);
|
await rpcStream.handleRequest(rpcRequest);
|
||||||
} catch (rpcError) {
|
} catch (rpcError) {
|
||||||
socket.write(
|
socket.write(
|
||||||
encodeMessage({
|
encodeMessage({
|
||||||
@@ -121,7 +121,7 @@ export async function startIpcServer(handler: IpcRequestHandler): Promise<Server
|
|||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
socket.once("close", () => attachment.close());
|
socket.once("close", () => rpcStream.close());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,24 +69,31 @@ export function createRpcProcessInstance(options: { cwd: string }): RpcProcessIn
|
|||||||
|
|
||||||
const handleLine = (line: string) => {
|
const handleLine = (line: string) => {
|
||||||
const parsed = JSON.parse(line) as { type?: string; id?: string };
|
const parsed = JSON.parse(line) as { type?: string; id?: string };
|
||||||
if (parsed.type === "response") {
|
|
||||||
if (parsed.id) {
|
switch (parsed.type) {
|
||||||
|
case "response": {
|
||||||
|
if (!parsed.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const pending = pendingRequests.get(parsed.id);
|
const pending = pendingRequests.get(parsed.id);
|
||||||
if (pending) {
|
if (!pending) {
|
||||||
pendingRequests.delete(parsed.id);
|
return;
|
||||||
pending.resolve(parsed as RpcResponse);
|
}
|
||||||
|
pendingRequests.delete(parsed.id);
|
||||||
|
pending.resolve(parsed as RpcResponse);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "extension_ui_request": {
|
||||||
|
uiRequestHandler?.(parsed as RpcExtensionUIRequest);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
for (const listener of eventListeners) {
|
||||||
|
listener(parsed as AgentSessionEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parsed.type === "extension_ui_request") {
|
|
||||||
uiRequestHandler?.(parsed as RpcExtensionUIRequest);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const listener of eventListeners) {
|
|
||||||
listener(parsed as AgentSessionEvent);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { existsSync, mkdirSync, unlinkSync } from "node:fs";
|
import { existsSync, mkdirSync, unlinkSync } from "node:fs";
|
||||||
import { dirname } from "node:path";
|
import { dirname } from "node:path";
|
||||||
import { getSocketPath } from "./config.ts";
|
import { getSocketPath } from "./config.ts";
|
||||||
import { attachIpcInstance, handleIpcRequest } from "./handler.ts";
|
import { handleIpcRequest, openRpcStream } from "./handler.ts";
|
||||||
import { startIpcServer } from "./ipc/server.ts";
|
import { startIpcServer } from "./ipc/server.ts";
|
||||||
import { getRadiusOrchestratorBaseUrl, isRadiusEnabled, radiusPresence } from "./radius.ts";
|
import { getRadiusOrchestratorBaseUrl, isRadiusEnabled, radiusPresence } from "./radius.ts";
|
||||||
import { supervisor } from "./supervisor.ts";
|
import { supervisor } from "./supervisor.ts";
|
||||||
@@ -21,7 +21,7 @@ export async function serve(): Promise<void> {
|
|||||||
}
|
}
|
||||||
const server = await startIpcServer(
|
const server = await startIpcServer(
|
||||||
Object.assign(handleIpcRequest, {
|
Object.assign(handleIpcRequest, {
|
||||||
attach: attachIpcInstance,
|
openRpcStream,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
console.log(`orchestrator listening on ${socketPath}`);
|
console.log(`orchestrator listening on ${socketPath}`);
|
||||||
|
|||||||
@@ -25,6 +25,26 @@ function cloneInstance(record: InstanceRecord): InstanceRecord {
|
|||||||
return { ...record };
|
return { ...record };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only refresh persisted session metadata after commands that can plausibly change
|
||||||
|
// the instance identity/details we store in instances.json. Most RPCs mutate transient
|
||||||
|
// runtime state only, so forcing a follow-up get_state after every command is wasted IO.
|
||||||
|
//
|
||||||
|
// - new_session / switch_session / fork / clone can change sessionId/sessionFile
|
||||||
|
// - set_session_name changes a persisted session detail we may want reflected externally
|
||||||
|
// - prompt can materialize or advance persisted session state after the child processes it
|
||||||
|
const SESSION_METADATA_COMMANDS: ReadonlySet<RpcCommand["type"]> = new Set([
|
||||||
|
"new_session",
|
||||||
|
"switch_session",
|
||||||
|
"fork",
|
||||||
|
"clone",
|
||||||
|
"set_session_name",
|
||||||
|
"prompt",
|
||||||
|
]);
|
||||||
|
|
||||||
|
function shouldRefreshSessionMetadata(command: RpcCommand): boolean {
|
||||||
|
return SESSION_METADATA_COMMANDS.has(command.type);
|
||||||
|
}
|
||||||
|
|
||||||
function isGetStateSuccess(
|
function isGetStateSuccess(
|
||||||
response: RpcResponse,
|
response: RpcResponse,
|
||||||
): response is Extract<
|
): response is Extract<
|
||||||
@@ -86,7 +106,7 @@ export class OrchestratorSupervisor {
|
|||||||
upsertInstance(instance);
|
upsertInstance(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
attachInstance(
|
openRpcStream(
|
||||||
instanceId: string,
|
instanceId: string,
|
||||||
onEvent: (event: AgentSessionEvent) => void,
|
onEvent: (event: AgentSessionEvent) => void,
|
||||||
onUiRequest: (request: RpcExtensionUIRequest) => void,
|
onUiRequest: (request: RpcExtensionUIRequest) => void,
|
||||||
@@ -106,7 +126,9 @@ export class OrchestratorSupervisor {
|
|||||||
return {
|
return {
|
||||||
handleRpc: async (command) => {
|
handleRpc: async (command) => {
|
||||||
const response = await live.rpc.send(command);
|
const response = await live.rpc.send(command);
|
||||||
await this.syncInstanceRecord(live);
|
if (shouldRefreshSessionMetadata(command)) {
|
||||||
|
await this.syncInstanceRecord(live);
|
||||||
|
}
|
||||||
return response;
|
return response;
|
||||||
},
|
},
|
||||||
handleUiResponse: (response) => {
|
handleUiResponse: (response) => {
|
||||||
@@ -204,7 +226,9 @@ export class OrchestratorSupervisor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const response = await live.rpc.send(command);
|
const response = await live.rpc.send(command);
|
||||||
await this.syncInstanceRecord(live);
|
if (shouldRefreshSessionMetadata(command)) {
|
||||||
|
await this.syncInstanceRecord(live);
|
||||||
|
}
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user