From 7cf456aa1c127d37e886b92254b7dae2f71784cd Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Tue, 1 Sep 2026 09:51:12 +0200 Subject: [PATCH] feat: remove experimental compatibility shims --- .../src/experimental/session-worker-manager.ts | 10 +++++++++- .../coding-agent/src/experimental/session-worker.ts | 6 ++---- .../test/experimental-session-worker-manager.test.ts | 7 ------- packages/server/README.md | 2 +- packages/server/src/errors.ts | 8 -------- packages/server/src/session-router.ts | 7 ++----- packages/server/src/types.ts | 2 +- packages/server/test/conformance.test.ts | 3 ++- 8 files changed, 17 insertions(+), 28 deletions(-) diff --git a/packages/coding-agent/src/experimental/session-worker-manager.ts b/packages/coding-agent/src/experimental/session-worker-manager.ts index adc3e15e5..c450b8bb6 100644 --- a/packages/coding-agent/src/experimental/session-worker-manager.ts +++ b/packages/coding-agent/src/experimental/session-worker-manager.ts @@ -461,7 +461,15 @@ export class SessionWorkerManager { try { const options: SessionWorkerOptions = { sessionDir: this.#sessionDir, - metadata, + metadata: { + id: metadata.id, + createdAt: metadata.createdAt, + storageVersion: metadata.storageVersion, + cwd: metadata.cwd, + path: metadata.path, + modifiedAt: metadata.modifiedAt, + ...(metadata.parentSessionId === undefined ? {} : { parentSessionId: metadata.parentSessionId }), + }, pluginManifestPaths: [...pluginManifestPaths], ...(this.#model ?? {}), }; diff --git a/packages/coding-agent/src/experimental/session-worker.ts b/packages/coding-agent/src/experimental/session-worker.ts index 45ec355c8..92a99aaed 100644 --- a/packages/coding-agent/src/experimental/session-worker.ts +++ b/packages/coding-agent/src/experimental/session-worker.ts @@ -78,7 +78,6 @@ export const SessionWorkerMetadataSchema = StrictObject({ path: Type.String(), modifiedAt: Type.Number(), parentSessionId: Type.Optional(Type.String()), - legacyParentSessionPath: Type.Optional(Type.String()), }); export const SessionWorkerOptionsSchema = StrictObject({ @@ -521,7 +520,7 @@ export type CreateSessionWorkerHarness = ( session: Session, options: SessionWorkerOptions, executionEnv: NodeExecutionEnv, -) => Promise; +) => Promise; async function run(options: SessionWorkerOptions, createHarness: CreateSessionWorkerHarness): Promise { const { sessionDir, metadata } = options; @@ -545,8 +544,7 @@ async function run(options: SessionWorkerOptions, createHarness: CreateSessionWo let services: SessionWorkerServices | undefined; try { session = await repo.open(metadata, TODO_CONTEXT); - const created = await createHarness(session, options, executionEnv); - const runtime: SessionWorkerRuntime = "harness" in created ? created : { harness: created }; + const runtime = await createHarness(session, options, executionEnv); harness = runtime.harness; lane = runtime.lane ?? (await harness.lane("main", TODO_CONTEXT)); services = await createSessionWorkerServices({ diff --git a/packages/coding-agent/test/experimental-session-worker-manager.test.ts b/packages/coding-agent/test/experimental-session-worker-manager.test.ts index 087a80d7e..a4d2ffed6 100644 --- a/packages/coding-agent/test/experimental-session-worker-manager.test.ts +++ b/packages/coding-agent/test/experimental-session-worker-manager.test.ts @@ -219,8 +219,6 @@ describe("Session worker operations", () => { }); }); }; - if (attachment.invokeService === undefined) throw new Error("Missing service attachment"); - await expect(attachment.invokeService(serviceCall, () => {}, BACKGROUND_CONTEXT)).resolves.toEqual({ accepted: true, }); @@ -257,8 +255,6 @@ describe("Session worker operations", () => { }), ); }; - if (attachment.invokeService === undefined) throw new Error("Missing service attachment"); - await expect(attachment.invokeService(serviceCall, () => {}, BACKGROUND_CONTEXT)).rejects.toThrow( /mismatched operation response/, ); @@ -288,8 +284,6 @@ describe("Session worker operations", () => { }), ); }; - if (attachment.invokeService === undefined) throw new Error("Missing service attachment"); - await expect(attachment.invokeService(serviceCall, () => {}, BACKGROUND_CONTEXT)).rejects.toThrow( /invalid operation response/, ); @@ -300,7 +294,6 @@ describe("Session worker operations", () => { test("rejects pending service calls on replacement without stopping the worker", async () => { const { coordinator, workers, attachment } = await createAttachedWorker(); coordinator.onSend = () => {}; - if (attachment.invokeService === undefined) throw new Error("Missing service attachment"); const calling = attachment.invokeService(serviceCall, () => {}, BACKGROUND_CONTEXT); workers.detach(); diff --git a/packages/server/README.md b/packages/server/README.md index 7dfffb50e..103016555 100644 --- a/packages/server/README.md +++ b/packages/server/README.md @@ -2,7 +2,7 @@ Experimental local server for the new durable Session and Agent Harness interfaces. -The current slice supports server- and Session-scoped facet-service routing and multi-presentation attachment. `RoutedServerServiceHost.attachClient()` creates one connection-scoped server service endpoint with narrow attachment-management capabilities. `RoutedSessionHandle.attachClient()` returns a presentation-scoped Session capability. Its optional `invokeService()` forwards an opaque service/member envelope to the selected Session endpoint; the server validates the attachment route but does not load the facet contract. +The current slice supports server- and Session-scoped facet-service routing and multi-presentation attachment. `RoutedServerServiceHost.attachClient()` creates one connection-scoped server service endpoint with narrow attachment-management capabilities. `RoutedSessionHandle.attachClient()` returns a presentation-scoped Session capability. Its `invokeService()` forwards an opaque service/member envelope to the selected Session endpoint; the server validates the attachment route but does not load the facet contract. - server service calls and subscriptions route opaquely through the connection's `RoutedServerServiceAttachment`; - the application-owned `SessionDirectory` projects the private catalog into replicated presentation-safe state; diff --git a/packages/server/src/errors.ts b/packages/server/src/errors.ts index 22c2a4007..26b688b59 100644 --- a/packages/server/src/errors.ts +++ b/packages/server/src/errors.ts @@ -6,7 +6,6 @@ type ServerOperationErrorCode = | "session_not_found" | "session_ambiguous" | "session_not_attached" - | "not_supported" | "server_draining"; export const INTERNAL_SERVER_ERROR_MESSAGE = "Internal server error"; @@ -50,13 +49,6 @@ export class SessionNotAttachedError extends ServerError { } } -export class NotSupportedError extends ServerError { - constructor(message: string) { - super("not_supported", message); - this.name = "NotSupportedError"; - } -} - export class ServerDrainingError extends ServerError { constructor() { super("server_draining", "Server is draining"); diff --git a/packages/server/src/session-router.ts b/packages/server/src/session-router.ts index b9df30e87..85979d69c 100644 --- a/packages/server/src/session-router.ts +++ b/packages/server/src/session-router.ts @@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto"; import type { JsonValue, ServiceCall, ServiceProviderUpdate } from "@earendil-works/chord"; import { BACKGROUND_CONTEXT, type Context, type SessionMetadata } from "@earendil-works/pi-agent-core"; import type { RpcTarget, SessionTarget } from "@earendil-works/pi-protocol"; -import { NotSupportedError, ServerDrainingError, SessionNotAttachedError } from "./errors.ts"; +import { ServerDrainingError, SessionNotAttachedError } from "./errors.ts"; import type { RoutedSessionAttachment, RoutedSessionHandle, ServerHost } from "./types.ts"; class SessionCleanupError extends AggregateError {} @@ -204,10 +204,7 @@ export class SessionRouter context: Context, ): Promise<{ result: Promise }> { const attachment = this.requireAttachment(client, target); - const invoke = attachment.lease?.invokeService; - if (invoke === undefined) throw new NotSupportedError("Routed Session does not support plugin services"); - const result = invoke.call( - attachment.lease, + const result = attachment.lease!.invokeService( call, (subscriptionId, update, updateContext) => publish(subscriptionId, update, updateContext), context, diff --git a/packages/server/src/types.ts b/packages/server/src/types.ts index de2c2f163..17567c2c7 100644 --- a/packages/server/src/types.ts +++ b/packages/server/src/types.ts @@ -17,7 +17,7 @@ export type MaybePromise = T | Promise; /** One presentation connection's live capability for a hosted Session. */ export interface RoutedSessionAttachment { /** Route one contract-agnostic service operation to the attached Session endpoint. */ - invokeService?( + invokeService( call: ServiceCall, publish: (subscriptionId: string, update: ServiceProviderUpdate, context: Context) => MaybePromise, context: Context, diff --git a/packages/server/test/conformance.test.ts b/packages/server/test/conformance.test.ts index 5c4ce8d91..49a1fd907 100644 --- a/packages/server/test/conformance.test.ts +++ b/packages/server/test/conformance.test.ts @@ -118,7 +118,7 @@ describe("Session protocol", () => { openSession: async (candidate) => { received = candidate; return { - attachClient: () => ({ release() {} }), + attachClient: () => ({ invokeService: async () => undefined, release() {} }), close: async () => {}, }; }, @@ -413,6 +413,7 @@ describe("routed Session acquisition failures", () => { acquiring.resolve(undefined); await continueAcquiring.promise; return { + invokeService: async () => undefined, release: () => { releaseCount += 1; },