mirror of
https://github.com/morluto/rea.git
synced 2026-11-07 05:56:19 -10:00
fix(kuna): give actionable lookup recovery (#8656)
* fix(kuna): give actionable lookup recovery * fix(kuna): keep lookup advice operation neutral * style(kuna): apply repository formatter
This commit is contained in:
1 parent
6259ac41a4
commit
d496d803a4
2 files changed
+67
-2
No files matched your search
@@ -1057,6 +1057,9 @@ export class KunaSessionClient implements AnalysisClient {
|
||||
err(
|
||||
new AnalysisInputError(operation, {
|
||||
userMessage: kunaDataEntryMessage(entry, index.data.get(entry)!),
|
||||
conformsToInputContract: true,
|
||||
remediationAction:
|
||||
"Inspect the data address with address_name or xrefs, or select a procedure entry from list_procedures. Do not repeat the unchanged call.",
|
||||
}),
|
||||
);
|
||||
const selected = (entry: KunaInventoryFunction) => {
|
||||
@@ -1076,6 +1079,9 @@ export class KunaSessionClient implements AnalysisClient {
|
||||
return err(
|
||||
new AnalysisInputError(operation, {
|
||||
userMessage: `${address} is not a procedure entry Kuna found; list_procedures shows the entries it found.`,
|
||||
conformsToInputContract: true,
|
||||
remediationAction:
|
||||
"Inspect list_procedures and select a discovered entry if it answers your question. An unlisted address is not proof of a function; REA cannot use it as a Kuna procedure in this session. Do not repeat the unchanged call.",
|
||||
}),
|
||||
);
|
||||
return refused(entry) ? dataRefusal(entry) : selected(entry);
|
||||
@@ -1088,9 +1094,20 @@ export class KunaSessionClient implements AnalysisClient {
|
||||
return dataRefusal(named[0]);
|
||||
return err(
|
||||
new AnalysisInputError(operation, {
|
||||
conformsToInputContract: true,
|
||||
remediationAction:
|
||||
matches.length === 0 && named.length === 0
|
||||
? field === "procedure"
|
||||
? "Use search_procedures or list_procedures to inspect Kuna's discovered entries, then select a matching entry. Do not repeat the unchanged call."
|
||||
: "Inspect the selected target for the intended address and use that address explicitly. Do not repeat the unchanged call."
|
||||
: matches.length === 0
|
||||
? "Inspect the data addresses with address_name or xrefs, or select a procedure entry from list_procedures. Do not repeat the unchanged call."
|
||||
: "Select the intended entry by its exact address. Do not repeat the unchanged call.",
|
||||
userMessage:
|
||||
matches.length === 0 && named.length === 0
|
||||
? `Kuna found no procedure named ${selector}; search_procedures finds similar names.`
|
||||
? field === "procedure"
|
||||
? `Kuna found no procedure named ${selector}; search_procedures finds similar names.`
|
||||
: `Kuna found no inventory entry named ${selector}.`
|
||||
: matches.length === 0
|
||||
? `${selector} names ${String(named.length)} Kuna entries that lie in Mach-O data regions (${named.map(({ address }) => address).join(", ")}); they are data, not procedures.`
|
||||
: `${selector} names ${String(matches.length)} Kuna entries (${matches.map(({ address }) => address).join(", ")}); select one by address.`,
|
||||
|
||||
@@ -201,7 +201,7 @@ test("traces a procedure found only by its alias through the composed feature tr
|
||||
test("omits a data entry an alias names while keeping the code entry that shares it", async ({
|
||||
mcp,
|
||||
}) => {
|
||||
const { search, observe } = await aliasSession(
|
||||
const { client, search, observe } = await aliasSession(
|
||||
mcp,
|
||||
"rea-kuna-alias-macho-",
|
||||
{
|
||||
@@ -234,4 +234,52 @@ test("omits a data entry an alias names while keeping the code entry that shares
|
||||
),
|
||||
);
|
||||
expect(await search({ pattern: "global_count" })).toEqual([]);
|
||||
const { error } = parseMcpToolError(
|
||||
await client.callTool({
|
||||
name: "procedure_address",
|
||||
arguments: { procedure: "global_count" },
|
||||
}),
|
||||
);
|
||||
expect(error.recovery).toBeUndefined();
|
||||
expect(error.remediation.action).toContain("address_name");
|
||||
});
|
||||
|
||||
test("reports lookup failures with recovery for the selected target, not the input schema", async ({
|
||||
mcp,
|
||||
}) => {
|
||||
const { client } = await aliasSession(mcp, "rea-kuna-lookup-recovery-", {
|
||||
functions: VERSIONED,
|
||||
});
|
||||
for (const [procedure, guidance] of [
|
||||
["0x1335", "list_procedures"],
|
||||
["absent_name", "search_procedures"],
|
||||
["audit_transform", "exact address"],
|
||||
]) {
|
||||
const response = await client.callTool({
|
||||
name: "procedure_address",
|
||||
arguments: { procedure },
|
||||
});
|
||||
const { error } = parseMcpToolError(response);
|
||||
expect(error.code).toBe("invalid_request");
|
||||
expect(error.recovery).toBeUndefined();
|
||||
expect(error.remediation.action).toContain(guidance);
|
||||
expect(error.remediation.action).not.toContain("input schema");
|
||||
}
|
||||
const assemblyError = parseMcpToolError(
|
||||
await client.callTool({
|
||||
name: "procedure_assembly",
|
||||
arguments: { procedure: "0x1335" },
|
||||
}),
|
||||
).error;
|
||||
expect(assemblyError.remediation.action).toContain("Kuna procedure");
|
||||
expect(assemblyError.remediation.action).not.toContain("decompile");
|
||||
const missingAddress = parseMcpToolError(
|
||||
await client.callTool({
|
||||
name: "xrefs",
|
||||
arguments: { address: "absent_name" },
|
||||
}),
|
||||
).error;
|
||||
expect(missingAddress.recovery).toBeUndefined();
|
||||
expect(missingAddress.message).toContain("no inventory entry named");
|
||||
expect(missingAddress.remediation.action).toContain("address");
|
||||
});
|
||||
Reference in new issue
Block a user