mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 17:30:31 +00:00
Inline chat server request adapters
This commit is contained in:
parent
1e3e4c9f84
commit
1b95c91034
11 changed files with 66 additions and 76 deletions
|
|
@ -94,10 +94,10 @@ const chatAppServerProtocolBoundaryBannedModules = nonAppServerBannedAppServerPr
|
|||
const chatAppServerProtocolBoundaryBannedImportPatterns = chatAppServerProtocolBoundaryBannedModules.flatMap((moduleName) =>
|
||||
importBoundaryPatterns(`app-server/protocol/${moduleName}`, `src/app-server/protocol/${moduleName}`, 6),
|
||||
);
|
||||
const chatAppServerRequestBridgeBannedModules = nonAppServerBannedAppServerProtocolModules.filter(
|
||||
const chatAppServerRequestBoundaryBannedModules = nonAppServerBannedAppServerProtocolModules.filter(
|
||||
(moduleName) => moduleName !== "server-requests",
|
||||
);
|
||||
const chatAppServerRequestBridgeBannedImportPatterns = chatAppServerRequestBridgeBannedModules.flatMap((moduleName) =>
|
||||
const chatAppServerRequestBoundaryBannedImportPatterns = chatAppServerRequestBoundaryBannedModules.flatMap((moduleName) =>
|
||||
importBoundaryPatterns(`app-server/protocol/${moduleName}`, `src/app-server/protocol/${moduleName}`, 6),
|
||||
);
|
||||
const generatedAppServerThreadImportRestrictions = [
|
||||
|
|
@ -124,7 +124,10 @@ const chatAppServerProtocolBoundaryFiles = [
|
|||
"src/features/chat/app-server/inbound/notification-plan.ts",
|
||||
"src/features/chat/app-server/mappers/message-stream/turn-items.ts",
|
||||
];
|
||||
const chatAppServerRequestBridgeFiles = ["src/features/chat/app-server/requests/**/*.{ts,tsx}"];
|
||||
const chatAppServerRequestBoundaryFiles = [
|
||||
"src/features/chat/app-server/inbound/handler.ts",
|
||||
"src/features/chat/app-server/inbound/routing.ts",
|
||||
];
|
||||
const unsafeIteratorRestrictions = [
|
||||
{
|
||||
selector: "MemberExpression[property.name='value'][object.type='CallExpression'][object.callee.property.name='next']",
|
||||
|
|
@ -501,16 +504,16 @@ export default defineConfig([
|
|||
},
|
||||
},
|
||||
{
|
||||
files: chatAppServerRequestBridgeFiles,
|
||||
files: chatAppServerRequestBoundaryFiles,
|
||||
rules: {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
patterns: [
|
||||
{
|
||||
group: chatAppServerRequestBridgeBannedImportPatterns,
|
||||
group: chatAppServerRequestBoundaryBannedImportPatterns,
|
||||
message:
|
||||
"Chat request bridges may consume server request protocol projections only. Convert app-server payloads to chat pending request domain models at this boundary.",
|
||||
"Chat app-server request handling may consume server request protocol projections only. Convert app-server payloads to chat pending request domain models at this boundary.",
|
||||
},
|
||||
{
|
||||
group: generatedAppServerSourceImportPatterns,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,9 @@
|
|||
import type { RequestId, ServerNotification, ServerRequest } from "../../../../app-server/connection/rpc-messages";
|
||||
import {
|
||||
appServerApprovalResponse,
|
||||
appServerMcpElicitationResponse,
|
||||
appServerUserInputResponse,
|
||||
} from "../../../../app-server/protocol/server-requests";
|
||||
import type { McpServerStartupStatus } from "../../../../domain/server/diagnostics";
|
||||
import type { Thread } from "../../../../domain/threads/model";
|
||||
import type { ThreadConversationSummary } from "../../../../domain/threads/transcript";
|
||||
|
|
@ -17,9 +22,6 @@ import {
|
|||
type PendingRequestId,
|
||||
type PendingUserInput,
|
||||
} from "../../../../domain/pending-requests/model";
|
||||
import { approvalResponse } from "../requests/approval";
|
||||
import { mcpElicitationResponse } from "../requests/mcp-elicitation";
|
||||
import { userInputResponse } from "../requests/user-input";
|
||||
import {
|
||||
createApprovalResultItem,
|
||||
createMcpElicitationResultItem,
|
||||
|
|
@ -177,7 +179,7 @@ function handleAppServerLog(context: ChatInboundHandlerContext, message: string)
|
|||
function resolveApproval(context: ChatInboundHandlerContext, requestId: PendingRequestId, action: ApprovalAction): void {
|
||||
const approval = pendingApproval(context, requestId);
|
||||
if (!approval) return;
|
||||
if (!context.actions.respondToServerRequest(approval.requestId, approvalResponse(approval, action))) {
|
||||
if (!context.actions.respondToServerRequest(approval.requestId, appServerApprovalResponse(approval, action))) {
|
||||
addSystemMessage(context, cannotSendApprovalResponseMessage());
|
||||
return;
|
||||
}
|
||||
|
|
@ -187,7 +189,7 @@ function resolveApproval(context: ChatInboundHandlerContext, requestId: PendingR
|
|||
function resolveUserInput(context: ChatInboundHandlerContext, requestId: PendingRequestId, answers: Record<string, string>): void {
|
||||
const input = pendingUserInput(context, requestId);
|
||||
if (!input) return;
|
||||
if (!context.actions.respondToServerRequest(input.requestId, userInputResponse(input, answers))) {
|
||||
if (!context.actions.respondToServerRequest(input.requestId, appServerUserInputResponse(input.params.questions, answers))) {
|
||||
addSystemMessage(context, cannotSendUserInputMessage());
|
||||
return;
|
||||
}
|
||||
|
|
@ -216,7 +218,7 @@ function resolveMcpElicitation(context: ChatInboundHandlerContext, requestId: Pe
|
|||
const elicitation = pendingMcpElicitation(context, requestId);
|
||||
if (!elicitation) return;
|
||||
const content = action === "accept" ? contentForPendingMcpElicitation(elicitation, state(context).requests.mcpElicitationDrafts) : null;
|
||||
if (!context.actions.respondToServerRequest(elicitation.requestId, mcpElicitationResponse(action, content))) {
|
||||
if (!context.actions.respondToServerRequest(elicitation.requestId, appServerMcpElicitationResponse(action, content))) {
|
||||
addSystemMessage(context, cannotSendMcpElicitationMessage());
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
import type { ServerNotification, ServerRequest } from "../../../../app-server/connection/rpc-messages";
|
||||
import {
|
||||
appServerApprovalRequest,
|
||||
appServerMcpElicitationRequest,
|
||||
appServerUserInputRequest,
|
||||
} from "../../../../app-server/protocol/server-requests";
|
||||
import type { PendingApproval, PendingMcpElicitation, PendingUserInput } from "../../../../domain/pending-requests/model";
|
||||
import { toPendingApproval } from "../requests/approval";
|
||||
import { toPendingMcpElicitation } from "../requests/mcp-elicitation";
|
||||
import { toPendingUserInput } from "../requests/user-input";
|
||||
|
||||
export interface ActiveRouteScope {
|
||||
activeThreadId: string | null;
|
||||
|
|
@ -234,17 +236,17 @@ export function routeServerRequest(request: ServerRequest, scope: ActiveRouteSco
|
|||
|
||||
switch (SERVER_REQUEST_ROUTE_KIND_BY_METHOD[request.method]) {
|
||||
case "approval": {
|
||||
const approval = toPendingApproval(request);
|
||||
const approval = appServerApprovalRequest(request);
|
||||
if (approval) return { kind: "approval", request, approval };
|
||||
return { kind: "unsupported", request };
|
||||
}
|
||||
case "userInput": {
|
||||
const input = toPendingUserInput(request);
|
||||
const input = appServerUserInputRequest(request);
|
||||
if (input) return { kind: "userInput", request, input };
|
||||
return { kind: "unsupported", request };
|
||||
}
|
||||
case "mcpElicitation": {
|
||||
const elicitation = toPendingMcpElicitation(request);
|
||||
const elicitation = appServerMcpElicitationRequest(request);
|
||||
if (elicitation) return { kind: "mcpElicitation", request, elicitation };
|
||||
return { kind: "unsupported", request };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
import type { ServerRequest } from "../../../../app-server/connection/rpc-messages";
|
||||
import {
|
||||
appServerApprovalRequest,
|
||||
appServerApprovalResponse,
|
||||
type AppServerApprovalResponse,
|
||||
} from "../../../../app-server/protocol/server-requests";
|
||||
import type { ApprovalAction, PendingApproval } from "../../../../domain/pending-requests/model";
|
||||
|
||||
export function toPendingApproval(request: ServerRequest): PendingApproval | null {
|
||||
return appServerApprovalRequest(request);
|
||||
}
|
||||
|
||||
export function approvalResponse(approval: PendingApproval, action: ApprovalAction): AppServerApprovalResponse {
|
||||
return appServerApprovalResponse(approval, action);
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
import type { ServerRequest } from "../../../../app-server/connection/rpc-messages";
|
||||
import {
|
||||
appServerMcpElicitationRequest,
|
||||
appServerMcpElicitationResponse,
|
||||
type AppServerMcpElicitationResponse,
|
||||
} from "../../../../app-server/protocol/server-requests";
|
||||
import type { McpElicitationAction, McpElicitationContentValue, PendingMcpElicitation } from "../../../../domain/pending-requests/model";
|
||||
|
||||
export function toPendingMcpElicitation(request: ServerRequest): PendingMcpElicitation | null {
|
||||
return appServerMcpElicitationRequest(request);
|
||||
}
|
||||
|
||||
export function mcpElicitationResponse(
|
||||
action: McpElicitationAction,
|
||||
content: Record<string, McpElicitationContentValue> | null,
|
||||
): AppServerMcpElicitationResponse {
|
||||
return appServerMcpElicitationResponse(action, content);
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
import type { ServerRequest } from "../../../../app-server/connection/rpc-messages";
|
||||
import {
|
||||
appServerUserInputRequest,
|
||||
appServerUserInputResponse,
|
||||
type AppServerUserInputResponse,
|
||||
} from "../../../../app-server/protocol/server-requests";
|
||||
import type { PendingUserInput } from "../../../../domain/pending-requests/model";
|
||||
|
||||
export function toPendingUserInput(request: ServerRequest): PendingUserInput | null {
|
||||
return appServerUserInputRequest(request);
|
||||
}
|
||||
|
||||
export function userInputResponse(input: PendingUserInput, answers: Record<string, string>): AppServerUserInputResponse {
|
||||
return appServerUserInputResponse(input.params.questions, answers);
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { appServerUserInputRequest as toPendingUserInput } from "../../../../../src/app-server/protocol/server-requests";
|
||||
import { createChatState } from "../../../../../src/features/chat/application/state/root-reducer";
|
||||
import { createChatStateStore } from "../../../../../src/features/chat/application/state/store";
|
||||
import { createPendingRequestActions } from "../../../../../src/features/chat/application/pending-requests/pending-request-actions";
|
||||
import { toPendingUserInput } from "../../../../../src/features/chat/app-server/requests/user-input";
|
||||
import type { ServerRequest } from "../../../../../src/app-server/connection/rpc-messages";
|
||||
|
||||
function expectPresent<T>(value: T | null | undefined): T {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { approvalResponse, toPendingApproval } from "../../../../../src/features/chat/app-server/requests/approval";
|
||||
import {
|
||||
appServerApprovalRequest as toPendingApproval,
|
||||
appServerApprovalResponse as approvalResponse,
|
||||
} from "../../../../../src/app-server/protocol/server-requests";
|
||||
import { approvalDetails, approvalSummary, approvalTitle } from "../../../../../src/features/chat/domain/pending-requests/approval";
|
||||
import { createApprovalResultItem } from "../../../../../src/features/chat/domain/pending-requests/result-items";
|
||||
import type { CommandApprovalDecision } from "../../../../../src/domain/pending-requests/model";
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
appServerMcpElicitationRequest as toPendingMcpElicitation,
|
||||
appServerMcpElicitationResponse as mcpElicitationResponse,
|
||||
} from "../../../../../src/app-server/protocol/server-requests";
|
||||
import type { ServerRequest } from "../../../../../src/app-server/connection/rpc-messages";
|
||||
import { toPendingMcpElicitation, mcpElicitationResponse } from "../../../../../src/features/chat/app-server/requests/mcp-elicitation";
|
||||
import { contentForPendingMcpElicitation, mcpElicitationDraftKey } from "../../../../../src/domain/pending-requests/model";
|
||||
|
||||
function expectPresent<T>(value: T | null | undefined): T {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
appServerUserInputRequest as toPendingUserInput,
|
||||
appServerUserInputResponse,
|
||||
} from "../../../../../src/app-server/protocol/server-requests";
|
||||
import { answersForPendingUserInput, questionDefaultAnswer } from "../../../../../src/domain/pending-requests/model";
|
||||
import { toPendingUserInput, userInputResponse } from "../../../../../src/features/chat/app-server/requests/user-input";
|
||||
import {
|
||||
pendingRequestFocusSignature,
|
||||
pendingRequestsSignature,
|
||||
|
|
@ -41,7 +44,7 @@ describe("user input model", () => {
|
|||
expect(questionDefaultAnswer(expectPresent(request.params.questions[0]))).toBe("Recommended");
|
||||
expect(answersForPendingUserInput(input, new Map())).toEqual({ direction: "Recommended" });
|
||||
expect(answersForPendingUserInput(input, new Map([["7:direction", "Left"]]))).toEqual({ direction: "Left" });
|
||||
expect(userInputResponse(input, { direction: "Recommended" })).toEqual({
|
||||
expect(appServerUserInputResponse(input.params.questions, { direction: "Recommended" })).toEqual({
|
||||
answers: { direction: { answers: ["Recommended"] } },
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ export type Change = FileUpdateChange;
|
|||
expect(messages).toContain("no-restricted-imports");
|
||||
});
|
||||
|
||||
it("reports server request protocol imports outside app-server and chat request bridges", async () => {
|
||||
it("reports server request protocol imports outside app-server and chat request boundaries", async () => {
|
||||
const messages = await lintSource(
|
||||
"src/features/chat/panel/surface/message-stream-presenter.ts",
|
||||
`
|
||||
|
|
@ -175,9 +175,17 @@ export const response = appServerUserInputResponse;
|
|||
expect(messages).toContain("no-restricted-imports");
|
||||
});
|
||||
|
||||
it("allows server request protocol imports in chat request bridges", async () => {
|
||||
const messages = await lintSource(
|
||||
"src/features/chat/app-server/requests/user-input.ts",
|
||||
it("allows server request protocol imports in chat inbound request boundaries", async () => {
|
||||
const routingMessages = await lintSource(
|
||||
"src/features/chat/app-server/inbound/routing.ts",
|
||||
`
|
||||
import { appServerUserInputResponse } from "../../../../app-server/protocol/server-requests";
|
||||
|
||||
export const response = appServerUserInputResponse;
|
||||
`,
|
||||
);
|
||||
const handlerMessages = await lintSource(
|
||||
"src/features/chat/app-server/inbound/handler.ts",
|
||||
`
|
||||
import { appServerUserInputResponse } from "../../../../app-server/protocol/server-requests";
|
||||
|
||||
|
|
@ -185,7 +193,21 @@ export const response = appServerUserInputResponse;
|
|||
`,
|
||||
);
|
||||
|
||||
expect(messages).not.toContain("no-restricted-imports");
|
||||
expect(routingMessages).not.toContain("no-restricted-imports");
|
||||
expect(handlerMessages).not.toContain("no-restricted-imports");
|
||||
});
|
||||
|
||||
it("reports server request protocol imports in non-boundary chat app-server modules", async () => {
|
||||
const messages = await lintSource(
|
||||
"src/features/chat/app-server/inbound/app-server-logs.ts",
|
||||
`
|
||||
import { appServerUserInputResponse } from "../../../../app-server/protocol/server-requests";
|
||||
|
||||
export const response = appServerUserInputResponse;
|
||||
`,
|
||||
);
|
||||
|
||||
expect(messages).toContain("no-restricted-imports");
|
||||
});
|
||||
|
||||
it("keeps generated app-server bindings out of non-exception protocol modules", async () => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue