This commit is contained in:
+109
-11
@@ -56,6 +56,31 @@ function makeCtx(hasUi: boolean, mode = hasUi ? "tui" : "print"): unknown {
|
||||
return { [HAS_UI]: hasUi, mode };
|
||||
}
|
||||
|
||||
function makeRpcCtx(responses: Array<string | undefined>) {
|
||||
const requests: Array<{
|
||||
title: string;
|
||||
options?: string[];
|
||||
placeholder?: string;
|
||||
}> = [];
|
||||
return {
|
||||
ctx: {
|
||||
[HAS_UI]: true,
|
||||
mode: "rpc",
|
||||
ui: {
|
||||
select(title: string, options: string[]) {
|
||||
requests.push({ title, options });
|
||||
return Promise.resolve(responses.shift());
|
||||
},
|
||||
input(title: string, placeholder?: string) {
|
||||
requests.push({ title, placeholder });
|
||||
return Promise.resolve(responses.shift());
|
||||
},
|
||||
},
|
||||
},
|
||||
requests,
|
||||
};
|
||||
}
|
||||
|
||||
function sampleParams(): AskParams {
|
||||
return {
|
||||
title: "Clarify next step",
|
||||
@@ -155,23 +180,96 @@ test("ask tool returns pending questions in non-interactive mode", async () => {
|
||||
assert.match(result.content[0].text, CUSTOM_OPTION_RE);
|
||||
});
|
||||
|
||||
test("ask tool does not open custom UI outside TUI mode", async () => {
|
||||
test("ask tool uses standard dialogs in RPC mode", async () => {
|
||||
const { tool } = registerMockTool();
|
||||
let customOpened = false;
|
||||
const { ctx, requests } = makeRpcCtx(["1. Speed"]);
|
||||
|
||||
const result = await tool.execute("call-1", sampleParams(), undefined, noop, {
|
||||
[HAS_UI]: true,
|
||||
mode: "rpc",
|
||||
ui: {
|
||||
custom() {
|
||||
customOpened = true;
|
||||
},
|
||||
const result = await tool.execute(
|
||||
"call-1",
|
||||
sampleParams(),
|
||||
undefined,
|
||||
noop,
|
||||
ctx
|
||||
);
|
||||
|
||||
assert.deepEqual(requests, [
|
||||
{
|
||||
title: "Goal: What should I optimize for?",
|
||||
options: ["1. Speed", "2. Safety", "3. Type your own"],
|
||||
},
|
||||
]);
|
||||
assert.equal(result.details.cancelled, false);
|
||||
assert.deepEqual(result.details.answers.goal, {
|
||||
indices: [0],
|
||||
labels: ["Speed"],
|
||||
values: ["speed"],
|
||||
});
|
||||
});
|
||||
|
||||
test("ask tool collects a custom answer through an RPC input dialog", async () => {
|
||||
const { tool } = registerMockTool();
|
||||
const { ctx, requests } = makeRpcCtx(["3. Type your own", "Balance both"]);
|
||||
|
||||
const result = await tool.execute(
|
||||
"call-1",
|
||||
sampleParams(),
|
||||
undefined,
|
||||
noop,
|
||||
ctx
|
||||
);
|
||||
|
||||
assert.deepEqual(requests[1], {
|
||||
title: "Goal: What should I optimize for?",
|
||||
placeholder: "Type your answer",
|
||||
});
|
||||
assert.deepEqual(result.details.answers.goal, {
|
||||
indices: [],
|
||||
labels: [],
|
||||
values: [],
|
||||
customText: "Balance both",
|
||||
});
|
||||
});
|
||||
|
||||
test("ask tool collects multiple selections through RPC dialogs", async () => {
|
||||
const { tool } = registerMockTool();
|
||||
const params = sampleParams();
|
||||
params.questions[0].type = "multi";
|
||||
const { ctx, requests } = makeRpcCtx([
|
||||
"1. [ ] Speed",
|
||||
"2. [ ] Safety",
|
||||
"3. Done",
|
||||
]);
|
||||
|
||||
const result = await tool.execute("call-1", params, undefined, noop, ctx);
|
||||
|
||||
assert.equal(requests.length, 3);
|
||||
assert.deepEqual(requests[1]?.options, [
|
||||
"1. [x] Speed",
|
||||
"2. [ ] Safety",
|
||||
"3. Done",
|
||||
"4. Type your own",
|
||||
]);
|
||||
assert.deepEqual(result.details.answers.goal, {
|
||||
indices: [0, 1],
|
||||
labels: ["Speed", "Safety"],
|
||||
values: ["speed", "safety"],
|
||||
});
|
||||
});
|
||||
|
||||
test("ask tool returns a cancelled RPC result when a dialog is dismissed", async () => {
|
||||
const { tool } = registerMockTool();
|
||||
const { ctx } = makeRpcCtx([undefined]);
|
||||
|
||||
const result = await tool.execute(
|
||||
"call-1",
|
||||
sampleParams(),
|
||||
undefined,
|
||||
noop,
|
||||
ctx
|
||||
);
|
||||
|
||||
assert.equal(customOpened, false);
|
||||
assert.equal(result.details.cancelled, true);
|
||||
assert.match(result.content[0].text, NON_INTERACTIVE_MESSAGE_RE);
|
||||
assert.deepEqual(result.details.answers, {});
|
||||
});
|
||||
|
||||
test("ask tool includes custom answer fallback for preview questions", async () => {
|
||||
|
||||
Reference in New Issue
Block a user