feat(client): advertise reasoning merge capability
This commit is contained in:
@@ -60,10 +60,12 @@ function createMockTransport() {
|
|||||||
return {
|
return {
|
||||||
transport,
|
transport,
|
||||||
sent,
|
sent,
|
||||||
triggerOpen: () => {
|
triggerOpen: (options?: { preserveSent?: boolean }) => {
|
||||||
onOpen();
|
onOpen();
|
||||||
// Ignore HELLO handshake payloads in assertions.
|
if (!options?.preserveSent) {
|
||||||
sent.length = 0;
|
// Ignore HELLO handshake payloads in assertions.
|
||||||
|
sent.length = 0;
|
||||||
|
}
|
||||||
onMessage(
|
onMessage(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
type: "session",
|
type: "session",
|
||||||
@@ -214,6 +216,35 @@ test("passes password as HTTP bearer header and WebSocket subprotocol", async ()
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("advertises reasoning_merge_enum in hello", async () => {
|
||||||
|
const logger = createMockLogger();
|
||||||
|
const mock = createMockTransport();
|
||||||
|
|
||||||
|
const client = new DaemonClient({
|
||||||
|
url: "ws://test",
|
||||||
|
clientId: "clsk_unit_test",
|
||||||
|
logger,
|
||||||
|
reconnect: { enabled: false },
|
||||||
|
transportFactory: () => mock.transport,
|
||||||
|
});
|
||||||
|
clients.push(client);
|
||||||
|
|
||||||
|
const connectPromise = client.connect();
|
||||||
|
mock.triggerOpen({ preserveSent: true });
|
||||||
|
await connectPromise;
|
||||||
|
|
||||||
|
expect(mock.sent).toHaveLength(1);
|
||||||
|
expect(JSON.parse(mock.sent[0] as string)).toEqual({
|
||||||
|
type: "hello",
|
||||||
|
clientId: "clsk_unit_test",
|
||||||
|
clientType: "cli",
|
||||||
|
protocolVersion: 1,
|
||||||
|
capabilities: {
|
||||||
|
reasoning_merge_enum: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test("does not reconnect after close when ensureConnected is called", async () => {
|
test("does not reconnect after close when ensureConnected is called", async () => {
|
||||||
const logger = createMockLogger();
|
const logger = createMockLogger();
|
||||||
const mock = createMockTransport();
|
const mock = createMockTransport();
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { z } from "zod";
|
import type { z } from "zod";
|
||||||
|
import { CLIENT_CAPS } from "../shared/client-capabilities.js";
|
||||||
import {
|
import {
|
||||||
AgentCreateFailedStatusPayloadSchema,
|
AgentCreateFailedStatusPayloadSchema,
|
||||||
AgentCreatedStatusPayloadSchema,
|
AgentCreatedStatusPayloadSchema,
|
||||||
@@ -3877,6 +3878,9 @@ export class DaemonClient {
|
|||||||
clientId: this.config.clientId,
|
clientId: this.config.clientId,
|
||||||
clientType: this.config.clientType ?? "cli",
|
clientType: this.config.clientType ?? "cli",
|
||||||
protocolVersion: 1,
|
protocolVersion: 1,
|
||||||
|
capabilities: {
|
||||||
|
[CLIENT_CAPS.reasoningMergeEnum]: true,
|
||||||
|
},
|
||||||
...(this.config.appVersion ? { appVersion: this.config.appVersion } : {}),
|
...(this.config.appVersion ? { appVersion: this.config.appVersion } : {}),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
encodeTerminalStreamFrame,
|
encodeTerminalStreamFrame,
|
||||||
TerminalStreamOpcode,
|
TerminalStreamOpcode,
|
||||||
} from "../shared/terminal-stream-protocol.js";
|
} from "../shared/terminal-stream-protocol.js";
|
||||||
|
import { CLIENT_CAPS } from "../shared/client-capabilities.js";
|
||||||
|
|
||||||
type SocketListener = (...args: unknown[]) => void;
|
type SocketListener = (...args: unknown[]) => void;
|
||||||
|
|
||||||
@@ -47,6 +48,7 @@ const sessionMock = vi.hoisted(() => {
|
|||||||
cleanup = vi.fn(async () => {});
|
cleanup = vi.fn(async () => {});
|
||||||
handleMessage = vi.fn(async () => {});
|
handleMessage = vi.fn(async () => {});
|
||||||
handleBinaryFrame = vi.fn((_frame: unknown) => {});
|
handleBinaryFrame = vi.fn((_frame: unknown) => {});
|
||||||
|
supports = vi.fn((capability: string) => this.args.clientCapabilities?.[capability] === true);
|
||||||
getClientActivity = vi.fn(() => null);
|
getClientActivity = vi.fn(() => null);
|
||||||
resetPeakInflight = vi.fn(() => {});
|
resetPeakInflight = vi.fn(() => {});
|
||||||
getRuntimeMetrics = vi.fn(() => ({
|
getRuntimeMetrics = vi.fn(() => ({
|
||||||
@@ -293,12 +295,16 @@ function createDownloadInProgressSpeechReadinessSnapshot(): SpeechReadinessSnaps
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function createHelloMessage(clientId: string) {
|
function createHelloMessage(
|
||||||
|
clientId: string,
|
||||||
|
options?: { capabilities?: Record<string, boolean> },
|
||||||
|
) {
|
||||||
return {
|
return {
|
||||||
type: "hello" as const,
|
type: "hello" as const,
|
||||||
clientId,
|
clientId,
|
||||||
clientType: "cli" as const,
|
clientType: "cli" as const,
|
||||||
protocolVersion: 1,
|
protocolVersion: 1,
|
||||||
|
...(options?.capabilities ? { capabilities: options.capabilities } : {}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,6 +406,34 @@ describe("relay external socket reconnect behavior", () => {
|
|||||||
await server.close();
|
await server.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("passes hello capabilities through to the created session", async () => {
|
||||||
|
const server = createServer();
|
||||||
|
const socket = new MockSocket();
|
||||||
|
|
||||||
|
await (server as unknown as WebSocketServerInternals).attachSocket(
|
||||||
|
socket,
|
||||||
|
createDirectRequest(),
|
||||||
|
);
|
||||||
|
socket.emit(
|
||||||
|
"message",
|
||||||
|
JSON.stringify(
|
||||||
|
createHelloMessage("client-capabilities", {
|
||||||
|
capabilities: { [CLIENT_CAPS.reasoningMergeEnum]: true },
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await Promise.resolve();
|
||||||
|
|
||||||
|
expect(sessionMock.instances).toHaveLength(1);
|
||||||
|
const session = sessionMock.instances[0]!;
|
||||||
|
expect(session.args.clientCapabilities).toEqual({
|
||||||
|
[CLIENT_CAPS.reasoningMergeEnum]: true,
|
||||||
|
});
|
||||||
|
expect(session.supports(CLIENT_CAPS.reasoningMergeEnum)).toBe(true);
|
||||||
|
|
||||||
|
await server.close();
|
||||||
|
});
|
||||||
|
|
||||||
test("closes pending connection when hello timeout elapses", async () => {
|
test("closes pending connection when hello timeout elapses", async () => {
|
||||||
const server = createServer();
|
const server = createServer();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user