mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
182 lines
5.4 KiB
TypeScript
182 lines
5.4 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import type { ServerRequest } from "../../src/app-server/connection/rpc-messages";
|
|
import {
|
|
appServerApprovalRequest,
|
|
appServerApprovalResponse,
|
|
appServerMcpElicitationRequest,
|
|
appServerMcpElicitationResponse,
|
|
appServerUserInputRequest,
|
|
appServerUserInputResponse,
|
|
} from "../../src/app-server/protocol/server-requests";
|
|
|
|
function expectPresent<T>(value: T | null | undefined): T {
|
|
if (value === null || value === undefined) throw new Error("Expected value to be present");
|
|
return value;
|
|
}
|
|
|
|
describe("app-server server request protocol adapters", () => {
|
|
it("classifies approval requests and builds approval responses", () => {
|
|
const request: ServerRequest = {
|
|
id: 2,
|
|
method: "item/permissions/requestApproval",
|
|
params: {
|
|
cwd: "/tmp/project",
|
|
threadId: "thread",
|
|
turnId: "turn",
|
|
itemId: "item",
|
|
environmentId: null,
|
|
startedAtMs: 1,
|
|
reason: "Need network",
|
|
permissions: { network: { enabled: true }, fileSystem: null },
|
|
},
|
|
};
|
|
|
|
const approval = expectPresent(appServerApprovalRequest(request));
|
|
|
|
expect(approval.kind).toBe("permission");
|
|
expect(appServerApprovalResponse(approval, "decline")).toEqual({ permissions: {}, scope: "turn" });
|
|
expect(appServerApprovalResponse(approval, "accept")).toEqual({
|
|
permissions: { network: { enabled: true } },
|
|
scope: "turn",
|
|
});
|
|
});
|
|
|
|
it("classifies user input requests and builds answer responses", () => {
|
|
const request: ServerRequest = {
|
|
id: 7,
|
|
method: "item/tool/requestUserInput",
|
|
params: {
|
|
threadId: "thread",
|
|
turnId: "turn",
|
|
itemId: "item",
|
|
questions: [
|
|
{
|
|
id: "direction",
|
|
header: "Direction",
|
|
question: "Which way?",
|
|
isOther: true,
|
|
isSecret: false,
|
|
options: [{ label: "Recommended", description: "Use the default path" }],
|
|
},
|
|
],
|
|
autoResolutionMs: null,
|
|
},
|
|
};
|
|
|
|
const input = expectPresent(appServerUserInputRequest(request));
|
|
|
|
expect(input.params.questions[0]?.id).toBe("direction");
|
|
expect(appServerUserInputResponse(input.params.questions, { direction: "Left" })).toEqual({
|
|
answers: { direction: { answers: ["Left"] } },
|
|
});
|
|
});
|
|
|
|
it("normalizes MCP form schema fields and response content", () => {
|
|
const input = expectPresent(appServerMcpElicitationRequest(formRequest()));
|
|
|
|
expect(input).toMatchObject({
|
|
requestId: 42,
|
|
params: {
|
|
mode: "form",
|
|
threadId: "thread",
|
|
turnId: null,
|
|
serverName: "github",
|
|
},
|
|
});
|
|
if (input.params.mode !== "form") throw new Error("Expected form mode");
|
|
expect(input.params.fields).toEqual(
|
|
expect.arrayContaining([
|
|
expect.objectContaining({ id: "title", type: "string", title: "Title", required: true, defaultValue: "Issue" }),
|
|
expect.objectContaining({ id: "notify", type: "boolean", defaultValue: true }),
|
|
expect.objectContaining({ id: "count", type: "integer", defaultValue: 2 }),
|
|
expect.objectContaining({
|
|
id: "labels",
|
|
type: "multi-select",
|
|
minItems: 1,
|
|
maxItems: 2,
|
|
options: [
|
|
{ value: "bug", label: "Bug" },
|
|
{ value: "docs", label: "Docs" },
|
|
],
|
|
}),
|
|
]),
|
|
);
|
|
|
|
expect(appServerMcpElicitationResponse("accept", { title: "Fix bug", labels: ["bug"] })).toEqual({
|
|
action: "accept",
|
|
content: { title: "Fix bug", labels: ["bug"] },
|
|
_meta: null,
|
|
});
|
|
expect(appServerMcpElicitationResponse("decline", { title: "Fix bug" })).toEqual({
|
|
action: "decline",
|
|
content: null,
|
|
_meta: null,
|
|
});
|
|
});
|
|
|
|
it("normalizes MCP url mode separately from form fields", () => {
|
|
expect(appServerMcpElicitationRequest(urlRequest())).toMatchObject({
|
|
requestId: 43,
|
|
params: {
|
|
mode: "url",
|
|
url: "https://example.com/confirm",
|
|
elicitationId: "elicit-1",
|
|
},
|
|
});
|
|
});
|
|
});
|
|
|
|
function formRequest(): ServerRequest {
|
|
return {
|
|
id: 42,
|
|
method: "mcpServer/elicitation/request",
|
|
params: {
|
|
threadId: "thread",
|
|
turnId: null,
|
|
serverName: "github",
|
|
mode: "form",
|
|
_meta: null,
|
|
message: "Provide issue details",
|
|
requestedSchema: {
|
|
type: "object",
|
|
required: ["title"],
|
|
properties: {
|
|
title: { type: "string", title: "Title", description: "Issue title", default: "Issue" },
|
|
labels: {
|
|
type: "array",
|
|
title: "Labels",
|
|
minItems: 1,
|
|
maxItems: 2,
|
|
items: {
|
|
anyOf: [
|
|
{ const: "bug", title: "Bug" },
|
|
{ const: "docs", title: "Docs" },
|
|
],
|
|
},
|
|
default: ["bug"],
|
|
},
|
|
notify: { type: "boolean", title: "Notify", default: true },
|
|
count: { type: "integer", title: "Count", default: 2 },
|
|
},
|
|
},
|
|
},
|
|
} as unknown as ServerRequest;
|
|
}
|
|
|
|
function urlRequest(): ServerRequest {
|
|
return {
|
|
id: 43,
|
|
method: "mcpServer/elicitation/request",
|
|
params: {
|
|
threadId: "thread",
|
|
turnId: "turn",
|
|
serverName: "github",
|
|
mode: "url",
|
|
_meta: null,
|
|
message: "Confirm in browser",
|
|
url: "https://example.com/confirm",
|
|
elicitationId: "elicit-1",
|
|
},
|
|
};
|
|
}
|