test/kiro-adapter-query.test.js
Rama main · réplica de lectura del repositorio original.
var test = require("node:test");
var assert = require("node:assert");
var { createKiroAdapter } = require("../lib/yoke/adapters/kiro");
var createKiroQueryHandle = require("../lib/yoke/adapters/kiro").contractTestKit.createQueryHandle;
test("v3 resume suppresses replay and configures supervised model selection", async function() {
var calls = [];
function FakeAcpServer() {
this.started = false;
this.handlers = [];
this.proc = null;
}
FakeAcpServer.prototype.start = function() {
this.started = true;
return Promise.resolve();
};
FakeAcpServer.prototype.addRequestHandler = function() {};
FakeAcpServer.prototype.addHandler = function(fn) {
var entry = { sessionId: null, fn: fn };
this.handlers.push(entry);
return entry;
};
FakeAcpServer.prototype.removeHandler = function(entry) {
var index = this.handlers.indexOf(entry);
if (index !== -1) this.handlers.splice(index, 1);
};
FakeAcpServer.prototype.send = function(method, params) {
calls.push({ method: method, params: params });
if (method === "initialize") return Promise.resolve({ protocolVersion: 1 });
if (method === "session/new") return Promise.resolve({ sessionId: "sess-fresh" });
if (method === "session/load") {
this.handlers[0].fn({
method: "session/update",
params: {
sessionId: params.sessionId,
update: { sessionUpdate: "agent_message_chunk", content: { type: "text", text: "OLD" } },
},
});
return Promise.resolve({});
}
if (method === "session/prompt") {
this.handlers[0].fn({
method: "session/update",
params: {
sessionId: params.sessionId,
update: { sessionUpdate: "agent_message_chunk", content: { type: "text", text: "NEW" } },
},
});
this.handlers[0].fn({
method: "session/update",
params: {
sessionId: params.sessionId,
update: {
sessionUpdate: "session_info_update",
_meta: { kiro: { kind: "context_usage", contextUsage: { usagePercentage: 10 } } },
},
},
});
return Promise.resolve({ stopReason: "end_turn" });
}
return Promise.resolve({});
};
FakeAcpServer.prototype.notify = function() {};
FakeAcpServer.prototype.stop = function() { this.started = false; };
var adapter = createKiroAdapter({
cwd: process.cwd(),
_binaryPath: "/fake/kiro-cli",
_AcpServerCtor: FakeAcpServer,
_fetchKasToken: function() { return Promise.resolve({ accessToken: "token" }); },
_fetchModels: function() {
return Promise.resolve({
models: ["auto"],
defaultModel: "auto",
contextWindows: { auto: 1000 },
});
},
});
await adapter.init();
var bridgeDescriptor = { name: "clay-tools", command: "/usr/bin/node", args: ["bridge.js", "--session", "7", "--query-generation", "2"] };
var freshHandle = await adapter.createQuery({
cwd: process.cwd(), model: "auto",
adapterOptions: { KIRO: { mode: "vibe", mcpServers: [bridgeDescriptor] } },
});
freshHandle.pushMessage("fresh");
for await (var freshEvent of freshHandle) { if (freshEvent.yokeType === "result") break; }
freshHandle.close();
var disabledHandle = await adapter.createQuery({
cwd: process.cwd(),
model: "auto",
skillOptions: { disable: true },
adapterOptions: { KIRO: { mode: "vibe", mcpServers: [bridgeDescriptor] } },
});
disabledHandle.pushMessage("disabled");
for await (var disabledEvent of disabledHandle) { if (disabledEvent.yokeType === "result") break; }
disabledHandle.close();
var handle = await adapter.createQuery({
cwd: process.cwd(),
model: "auto",
systemPrompt: "Base instructions",
appendSystemPrompt: "You are the Driver",
resumeSessionId: "sess-existing",
adapterOptions: { KIRO: { mode: "vibe", mcpServers: [bridgeDescriptor] } },
canUseTool: function() { return Promise.resolve({ behavior: "deny" }); },
});
handle.pushMessage("hello");
var text = "";
var result = null;
for await (var event of handle) {
if (event.yokeType === "text_delta") text += event.text;
if (event.yokeType === "result") { result = event; break; }
}
handle.close();
await adapter.shutdown();
assert.strictEqual(text, "NEW");
assert.strictEqual(result.sessionId, "sess-existing");
assert.strictEqual(result.usage.input_tokens, 100);
assert.ok(calls.some(function(call) {
return call.method === "session/set_config_option"
&& call.params.configId === "autopilot"
&& call.params.value === "off";
}));
assert.ok(calls.some(function(call) {
return call.method === "session/set_config_option"
&& call.params.configId === "model"
&& call.params.value === "auto";
}));
assert.ok(!calls.some(function(call) { return call.method === "session/set_model"; }));
var newCall = calls.find(function(call) { return call.method === "session/new"; });
var loadCall = calls.find(function(call) { return call.method === "session/load"; });
assert.deepEqual(newCall.params.mcpServers, [bridgeDescriptor]);
assert.deepEqual(loadCall.params.mcpServers, [bridgeDescriptor]);
var promptCall = calls.find(function(call) { return call.method === "session/prompt" && call.params.sessionId === "sess-existing"; });
assert.match(promptCall.params.prompt[0].text, /Base instructions/);
assert.match(promptCall.params.prompt[0].text, /You are the Driver/);
var disabledPromptCall = calls.find(function(call) {
return call.method === "session/prompt" && call.params.prompt[0].text === "disabled";
});
assert.ok(disabledPromptCall);
assert.doesNotMatch(disabledPromptCall.params.prompt[0].text, /Available shared skills/);
});
function createQueryServer(send) {
return {
started: true,
calls: [],
responses: [],
handlers: [],
send: send,
addHandler: function(fn) { var entry = { sessionId: null, fn: fn }; this.handlers.push(entry); return entry; },
removeHandler: function(entry) { var index = this.handlers.indexOf(entry); if (index !== -1) this.handlers.splice(index, 1); },
notify: function() {},
respond: function(id, result) { this.responses.push({ id: id, result: result }); },
};
}
test("Kiro resume and requested configuration failures stop before prompting", async function() {
var loadServer = createQueryServer(function(method, params) {
this.calls.push({ method: method, params: params });
if (method === "session/load") return Promise.reject(new Error("resume unavailable"));
return Promise.resolve({ sessionId: "must-not-replace" });
});
var loadHandle = createKiroQueryHandle(loadServer, {
cwd: process.cwd(), engine: "v3", model: "auto", resumeSessionId: "existing", mcpServers: [],
});
loadHandle.pushMessage("resume");
var loadErrors = [];
for await (var loadEvent of loadHandle) if (loadEvent.yokeType === "error") loadErrors.push(loadEvent.text);
assert.deepStrictEqual(loadErrors, ["resume unavailable"]);
assert.strictEqual(loadServer.calls.some(function(call) { return call.method === "session/new"; }), false);
assert.strictEqual(loadServer.calls.some(function(call) { return call.method === "session/prompt"; }), false);
var configServer = createQueryServer(function(method, params) {
this.calls.push({ method: method, params: params });
if (method === "session/new") return Promise.resolve({ sessionId: "fresh" });
if (method === "session/set_config_option" && params.configId === "model") return Promise.reject(new Error("model unavailable"));
return Promise.resolve({});
});
var configHandle = createKiroQueryHandle(configServer, {
cwd: process.cwd(), engine: "v3", model: "model-x", mcpServers: [],
});
configHandle.pushMessage("configured");
var configErrors = [];
for await (var configEvent of configHandle) if (configEvent.yokeType === "error") configErrors.push(configEvent.text);
assert.deepStrictEqual(configErrors, ["model unavailable"]);
assert.strictEqual(configServer.calls.some(function(call) { return call.method === "session/prompt"; }), false);
});
test("Kiro cancels permission requests with unrecognized option kinds", async function() {
var promptResolve;
var seenTool = null;
var server = createQueryServer(function(method, params) {
this.calls.push({ method: method, params: params });
if (method === "session/new") return Promise.resolve({ sessionId: "fresh" });
if (method === "session/prompt") return new Promise(function(resolve) { promptResolve = resolve; });
return Promise.resolve({});
});
var handle = createKiroQueryHandle(server, {
cwd: process.cwd(), engine: "v3", model: "auto", mcpServers: [],
canUseTool: function(toolName, input) { seenTool = { toolName: toolName, input: input }; return Promise.resolve({ behavior: "allow" }); },
});
handle.pushMessage("permission");
await new Promise(function(resolve) { setImmediate(resolve); });
server.handlers[0].fn({ method: "session/update", params: { sessionId: "fresh", update: {
sessionUpdate: "tool_call", toolCallId: "tool-1", name: "future_tool", title: "Unknown", rawInput: { value: 7 },
} } });
server.handlers[0].fn({ id: 91, method: "session/request_permission", params: {
sessionId: "fresh", toolCall: { toolCallId: "tool-1", title: "Unknown" },
options: [{ optionId: "first", kind: "future_allow" }, { optionId: "last", kind: "future_reject" }],
} });
await new Promise(function(resolve) { setImmediate(resolve); });
assert.deepStrictEqual(seenTool, { toolName: "future_tool", input: { value: 7 } });
assert.deepStrictEqual(server.responses, [{ id: 91, result: { outcome: { outcome: "cancelled" } } }]);
promptResolve({ stopReason: "cancelled" });
handle.endInput();
for await (var event of handle) {}
});