refactor(server): inline client capability parsing
With capability negotiation in place, the consumer-side tolerance pattern is unnecessary. Drop the dead readDeclaredClientCapabilities helper, inline the parsing in ClientCapabilities.fromHello, delete a tautological assertion in the relay reconnect test, and document the compatibility rules in architecture.md.
This commit is contained in:
@@ -8,11 +8,7 @@ import { basename, resolve, sep } from "path";
|
||||
import { homedir } from "node:os";
|
||||
import { z } from "zod";
|
||||
import type { ToolSet } from "ai";
|
||||
import {
|
||||
CLIENT_CAPS,
|
||||
readDeclaredClientCapabilities,
|
||||
type ClientCapability,
|
||||
} from "../shared/client-capabilities.js";
|
||||
import { CLIENT_CAPS, type ClientCapability } from "../shared/client-capabilities.js";
|
||||
import {
|
||||
isLegacyEditorTargetId,
|
||||
serializeAgentStreamEvent,
|
||||
@@ -731,20 +727,18 @@ function convertPCMToWavBuffer(
|
||||
return wavBuffer;
|
||||
}
|
||||
|
||||
class ClientCapabilities {
|
||||
private readonly supported: ReadonlySet<ClientCapability>;
|
||||
|
||||
constructor(capabilities: Iterable<ClientCapability>) {
|
||||
this.supported = new Set(capabilities);
|
||||
}
|
||||
|
||||
static fromHello(capabilities: Record<string, unknown> | null | undefined): ClientCapabilities {
|
||||
return new ClientCapabilities(readDeclaredClientCapabilities(capabilities));
|
||||
}
|
||||
|
||||
supports(capability: ClientCapability): boolean {
|
||||
return this.supported.has(capability);
|
||||
function parseClientCapabilities(
|
||||
capabilities: Record<string, unknown> | null | undefined,
|
||||
): ReadonlySet<ClientCapability> {
|
||||
if (!capabilities) {
|
||||
return new Set();
|
||||
}
|
||||
const known = new Set<ClientCapability>(Object.values(CLIENT_CAPS));
|
||||
return new Set(
|
||||
Object.entries(capabilities).flatMap(([key, value]) =>
|
||||
value === true && known.has(key as ClientCapability) ? [key as ClientCapability] : [],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -755,7 +749,7 @@ class ClientCapabilities {
|
||||
export class Session {
|
||||
private readonly clientId: string;
|
||||
private appVersion: string | null;
|
||||
private clientCapabilities: ClientCapabilities;
|
||||
private clientCapabilities: ReadonlySet<ClientCapability>;
|
||||
private readonly sessionId: string;
|
||||
private readonly onMessage: (msg: SessionOutboundMessage) => void;
|
||||
private readonly onBinaryMessage: ((frame: Uint8Array) => void) | null;
|
||||
@@ -912,7 +906,7 @@ export class Session {
|
||||
} = options;
|
||||
this.clientId = clientId;
|
||||
this.appVersion = appVersion ?? null;
|
||||
this.clientCapabilities = ClientCapabilities.fromHello(clientCapabilities);
|
||||
this.clientCapabilities = parseClientCapabilities(clientCapabilities);
|
||||
this.sessionId = uuidv4();
|
||||
this.onMessage = onMessage;
|
||||
this.onBinaryMessage = onBinaryMessage ?? null;
|
||||
@@ -985,11 +979,11 @@ export class Session {
|
||||
}
|
||||
|
||||
updateClientCapabilities(capabilities: Record<string, unknown> | null): void {
|
||||
this.clientCapabilities = ClientCapabilities.fromHello(capabilities);
|
||||
this.clientCapabilities = parseClientCapabilities(capabilities);
|
||||
}
|
||||
|
||||
supports(capability: ClientCapability): boolean {
|
||||
return this.clientCapabilities.supports(capability);
|
||||
return this.clientCapabilities.has(capability);
|
||||
}
|
||||
|
||||
async syncWorkspaceGitObserverForWorkspace(workspace: PersistedWorkspaceRecord): Promise<void> {
|
||||
|
||||
@@ -429,7 +429,6 @@ describe("relay external socket reconnect behavior", () => {
|
||||
expect(session.args.clientCapabilities).toEqual({
|
||||
[CLIENT_CAPS.reasoningMergeEnum]: true,
|
||||
});
|
||||
expect(session.supports(CLIENT_CAPS.reasoningMergeEnum)).toBe(true);
|
||||
|
||||
await server.close();
|
||||
});
|
||||
|
||||
@@ -3,21 +3,3 @@ export const CLIENT_CAPS = {
|
||||
} as const;
|
||||
|
||||
export type ClientCapability = (typeof CLIENT_CAPS)[keyof typeof CLIENT_CAPS];
|
||||
|
||||
const CLIENT_CAPABILITY_SET = new Set<string>(Object.values(CLIENT_CAPS));
|
||||
|
||||
export function isClientCapability(value: string): value is ClientCapability {
|
||||
return CLIENT_CAPABILITY_SET.has(value);
|
||||
}
|
||||
|
||||
export function readDeclaredClientCapabilities(
|
||||
capabilities: Record<string, unknown> | null | undefined,
|
||||
): ClientCapability[] {
|
||||
if (!capabilities) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return Object.entries(capabilities).flatMap(([key, value]) =>
|
||||
value === true && isClientCapability(key) ? [key] : [],
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user