Remove unused kernel seams (#1835)
1- Removed unused host-request capability helpers and the `kernelManagerRef` option from `IpythonToolOptions`.123456789101112131415161718192021222324252627282930313233343536373839import { createHostRequestHandler, type HostRequestContext, type HostRequestHandlerImplementation,} from "../src/core/kernel/index.js";
let nextSyntheticHostRequestId = 0;
/** Create a distinct, current dispatcher context for direct host-handler tests. */export function createSyntheticHostRequestContext(): HostRequestContext { const requestNumber = ++nextSyntheticHostRequestId; const controller = new AbortController(); return { requestId: `test-host-request-${requestNumber}`, generation: requestNumber, signal: controller.signal, isCurrent: () => !controller.signal.aborted, };}
/** Invoke a production-shaped handler with a synthetic dispatcher context. */export function invokeHostRequest( handler: HostRequestHandlerImplementation, payload: Record<string, unknown>,): Promise<Record<string, unknown>> { return handler(payload, createSyntheticHostRequestContext());}
/** Build staged context-aware fixture handlers through the production factory. */export function createTestHostHandlers< T extends Record< string, (payload: Record<string, unknown>, context: HostRequestContext) => Promise<Record<string, unknown>> >,>(handlers: T): Record<keyof T, HostRequestHandlerImplementation> { return Object.fromEntries( Object.entries(handlers).map(([type, handler]) => [type, createHostRequestHandler(handler)]), ) as unknown as Record<keyof T, HostRequestHandlerImplementation>;}12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152import { describe, expect, it } from "vitest";import { assertHostRequestHandler, createHostRequestHandler, type HostRequestContext,} from "../src/core/kernel/index.js";
describe("staged host-request handler authority", () => { it("rejects unary factory inputs before they run", () => { let calls = 0; const unary = async (_payload: Record<string, unknown>): Promise<Record<string, unknown>> => { calls += 1; return {}; };
expect(() => { // @ts-expect-error Staged handlers must accept dispatcher context as their second argument. createHostRequestHandler(unary); }).toThrow("host request handlers must accept payload and context"); expect(calls).toBe(0); });
it("rejects missing or invalid context before a genuine handler runs", async () => { let calls = 0; const handler = createHostRequestHandler(async (_payload, _context) => { calls += 1; return {}; });
assertHostRequestHandler(handler); // @ts-expect-error A staged handler cannot be invoked without dispatcher context. await expect(handler({})).rejects.toThrow("host request context is invalid"); await expect(handler({}, {} as HostRequestContext)).rejects.toThrow("host request context is invalid"); expect(calls).toBe(0); });
it("rejects copied-symbol forgeries through WeakSet provenance before they run", () => { const genuine = createHostRequestHandler(async (_payload, _context) => ({})); let calls = 0; const forged = async (): Promise<Record<string, unknown>> => { calls += 1; return {}; }; const brand = Object.getOwnPropertySymbols(genuine)[0]; Object.defineProperty(forged, brand, Object.getOwnPropertyDescriptor(genuine, brand)!);
expect(() => assertHostRequestHandler(forged)).toThrow( "host request handler is not a dispatcher-created capability", ); expect(calls).toBe(0); });});25 unmodified lines262728293031323031323637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710833343536289 unmodified linesExpand all25 unmodified lines
/** * Handles one typed request from Python code running in the kernel. * The returned record is sent back verbatim as the reply payload. * * The unary form is the dispatcher and registration contract; context-aware * handlers are declared separately below. */export type HostRequestHandler = (payload: Record<string, unknown>) => Promise<Record<string, unknown>>;
/** * Per-call authority supplied by the host-request dispatcher. * `requestId` is an opaque host-minted correlation token and `isCurrent()` * lets an implementation reject work after its authority is revoked. */export interface HostRequestContext { readonly requestId: string; readonly generation: number; readonly signal: AbortSignal; isCurrent(): boolean;}
const hostRequestHandlerBrand = Symbol("hostRequestHandler");
/** A context-aware implementation that must receive dispatcher authority. */export type HostRequestHandlerImplementation = ( payload: Record<string, unknown>, context: HostRequestContext,) => Promise<Record<string, unknown>>;
/** A factory-minted, context-aware host-request handler capability. */type HostRequestHandlerCapability = HostRequestHandlerImplementation & { readonly [hostRequestHandlerBrand]: true };
/** Runtime provenance cannot be recreated by copying the nominal symbol property. */const factoryCreatedHostRequestHandlers = new WeakSet<object>();
function assertGenuineHostRequestContext(context: unknown): asserts context is HostRequestContext { if ( typeof context !== "object" || context === null || typeof (context as HostRequestContext).requestId !== "string" || !(context as HostRequestContext).requestId || !Number.isSafeInteger((context as HostRequestContext).generation) || typeof (context as HostRequestContext).isCurrent !== "function" || typeof (context as HostRequestContext).signal !== "object" || (context as HostRequestContext).signal === null || typeof (context as HostRequestContext).signal.aborted !== "boolean" || typeof (context as HostRequestContext).signal.addEventListener !== "function" ) { throw new Error("host request context is invalid"); }}
/** * Creates a branded wrapper rather than mutating its implementation. Both its * generic shape and runtime arity reject unary callbacks before they can run. */export function createHostRequestHandler<T extends HostRequestHandlerImplementation>( implementation: T, ..._unaryRejection: Parameters<T> extends [unknown, unknown, ...unknown[]] ? [] : ["host request handlers must accept payload and context"]): HostRequestHandlerCapability { if (implementation.length < 2) throw new Error("host request handlers must accept payload and context"); const handler = async (payload: Record<string, unknown>, context: HostRequestContext) => { assertGenuineHostRequestContext(context); return implementation(payload, context); }; factoryCreatedHostRequestHandlers.add(handler); return Object.defineProperty(handler, hostRequestHandlerBrand, { value: true }) as HostRequestHandlerCapability;}
/** Reject copied-symbol and raw-function forgeries before they observe authenticated payloads. */export function assertHostRequestHandler(value: unknown): asserts value is HostRequestHandlerCapability { if ( typeof value !== "function" || (value as Partial<HostRequestHandlerCapability>)[hostRequestHandlerBrand] !== true || !factoryCreatedHostRequestHandlers.has(value) ) { throw new Error("host request handler is not a dispatcher-created capability"); }}
/** Host request handlers keyed by request type (e.g. "rlm.run", "goal.complete"). */export type HostRequestHandlers = Record<string, HostRequestHandler>;
/** Where and how to persist the kernel's user namespace so it survives resume. */289 unmodified linesExpand all285 unmodified linesExpand all28628728828929029129029129229320 unmodified lines31431531631732032132232332431831932032132235 unmodified lines3583593603613683693703623633643655 unmodified lines371372373374384385386375376377378138 unmodified linesExpand all517518519520533534535521522523524168 unmodified linesExpand all285 unmodified linesExpand all snapshotDir?: string; /** Resolves before this kernel starts — e.g. the previous provisioner's dispose, so a * /reload's old-kernel snapshot flush can't race the new kernel's restore. */ readyGate?: Promise<unknown>; /** Filled with the live kernel client after the first kernel start; cleared on construction. */ kernelManagerRef?: { current?: KernelClient }; /** * Fires once per kernel start when a previous session's namespace was revived * (some names restored or some failed), so the session can tell the model. */20 unmodified lines
constructor( private readonly cwd: string, private readonly options?: Omit<IpythonToolOptions, "provisioner">, ) { if (options?.kernelManagerRef) { options.kernelManagerRef.current = undefined; } } ) {}
/** The kernel manager, once a startup has completed successfully. */ get manager(): KernelClient | undefined { return this.startedManager;35 unmodified lines this.disposeController.abort(); const pending = this.managerPromise; this.managerPromise = undefined; this.startedManager = undefined; if (this.options?.kernelManagerRef) { this.options.kernelManagerRef.current = undefined; } if (!pending) return; try { const m = await pending; await m.dispose();5 unmodified lines async kill(): Promise<void> { const pending = this.managerPromise; this.managerPromise = undefined; this.startedManager = undefined; if (this.options?.kernelManagerRef) { this.options.kernelManagerRef.current = undefined; } if (!pending) return; try { const m = await pending; await m.kill();138 unmodified linesExpand all if (pendingRestore) { this._lastRestore = pendingRestore; this.options?.onRestore?.(pendingRestore); } if (this.options?.kernelManagerRef) { this.options.kernelManagerRef.current = m; } return m; } finally { startupAbort.cleanup(); }168 unmodified linesExpand all