test(apps): cover the modern MRTR leg of app-rendered elicitations
Both review findings from round two. The routing change sits in the funnel BOTH entry points share, but only the legacy inbound handler was driven by a test — the modern leg, where an elicitation arrives as an `input_required` result the MRTR driver unpacks and retries, was covered by construction alone. Adds `mrtr_app_choose_option` (a modern MRTR tool whose *embedded* elicitation carries `_meta.ui.resourceUri`) and drives it live over a real transport: the app answers, the retry carries that answer through `inputResponses`, and the server echoes it back as the tool's result. A second case cancels the tool call while the app is up and asserts the request-scoped signal aborts; a third runs the same tool against a modern server that never advertised the capability and asserts the native queue takes it. The cancellation case turned up a real gap: `tryAppElicitation` mounted an app for an already-aborted signal (the caller cancelled during an earlier MRTR round), leaving a modal nobody was waiting on and a promise that could never settle. It now throws the abort straight through. Also fixes the smoke count in the root README, which still said "two" headless-Chromium smokes and then introduced a third. Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
7c77c2b15f
commit
44010c313b
2 changed files with 196 additions and 5 deletions
|
|
@ -57,6 +57,7 @@ import {
|
|||
createMcpAppDemoResource,
|
||||
createAppElicitationTool,
|
||||
createAppElicitationResource,
|
||||
createMrtrAppElicitationTool,
|
||||
createArchitectureResource,
|
||||
createTestCwdResource,
|
||||
createTestEnvResource,
|
||||
|
|
@ -227,6 +228,8 @@ function resolveToolPreset(
|
|||
return createMcpAppDemoTool();
|
||||
case "app_choose_option":
|
||||
return createAppElicitationTool();
|
||||
case "mrtr_app_choose_option":
|
||||
return createMrtrAppElicitationTool();
|
||||
default:
|
||||
throw new Error(`Unknown tool preset: ${name}`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -641,6 +641,66 @@ export function createAppElicitationTool(): ToolDefinition {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The modern (2026-07-28) counterpart of {@link createAppElicitationTool}: an
|
||||
* MRTR tool whose EMBEDDED elicitation carries `_meta.ui.resourceUri` (#1854).
|
||||
*
|
||||
* The two paths reach the Inspector completely differently — a server→client
|
||||
* `elicitation/create` request on the legacy leg, an `input_required` result
|
||||
* the client unpacks and retries on the modern one — and the routing decision
|
||||
* has to be identical on both. It is, because both funnel through the same
|
||||
* `enqueuePendingElicitation`; this fixture is what lets a test prove that
|
||||
* rather than assert it.
|
||||
*
|
||||
* Completes on the retry by echoing the `ElicitResult` the app produced, so a
|
||||
* caller can see the app's answer round-trip through `inputResponses`.
|
||||
*/
|
||||
export function createMrtrAppElicitationTool(): ToolDefinition {
|
||||
return {
|
||||
name: "mrtr_app_choose_option",
|
||||
description:
|
||||
"Modern MRTR tool whose embedded elicitation offers an MCP App to render the form",
|
||||
inputSchema: {
|
||||
prompt: z.string().optional().describe("Message shown above the choice"),
|
||||
},
|
||||
handler: async (
|
||||
params: Record<string, unknown>,
|
||||
_context?: TestServerContext,
|
||||
extra?: HandlerExtra,
|
||||
) => {
|
||||
const responses = extra?.inputResponses;
|
||||
if (!responses || responses.choice === undefined) {
|
||||
return inputRequired({
|
||||
inputRequests: {
|
||||
choice: inputRequired.elicit({
|
||||
message:
|
||||
typeof params.prompt === "string"
|
||||
? params.prompt
|
||||
: "Choose option A or B.",
|
||||
requestedSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
choice: {
|
||||
type: "string",
|
||||
enum: ["option-a", "option-b"],
|
||||
title: "Choice",
|
||||
},
|
||||
},
|
||||
required: ["choice"],
|
||||
},
|
||||
_meta: { ui: { resourceUri: APP_ELICITATION_URI } },
|
||||
}),
|
||||
},
|
||||
requestState: `mrtr-app:${++mrtrMintCount}`,
|
||||
});
|
||||
}
|
||||
return toToolResult(
|
||||
`Elicitation response: ${JSON.stringify(responses.choice)}`,
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an "mrtr_confirm" tool exercising the modern (2026-07-28) multi
|
||||
* round-trip request (MRTR) flow. On the first call it returns an
|
||||
|
|
|
|||
Loading…
Reference in a new issue