mirror of
https://github.com/morluto/rea.git
synced 2026-11-15 11:13:21 +00:00
fix(setup): stop writing the default compact input profile for Kimi and LM Studio (#10559)
* fix(setup): stop writing the default compact input profile for Kimi and LM Studio The server already advertises compact input schemas when REA_MCP_INPUT_SCHEMA_PROFILE is unset, so setup no longer adds that value to Kimi Code and LM Studio registrations, and doctor/status no longer report a registration without it as stale. Explicit stored or setup-environment profiles are still preserved. Refs #10514 * fix(setup): validate LM Studio registration environment * test(hopper): retry cleanup after confirmed application exit
This commit is contained in:
1 parent
a0d96e520e
commit
6c062c9c2a
7 files changed
+57
-63
No files matched your search
@@ -427,18 +427,12 @@ client environment overrides remain intact unless setup supplies the same key.
|
||||
You can edit `startupTimeoutMs` and `toolTimeoutMs` there; doctor keeps positive
|
||||
caller-selected values aligned and reports a non-blocking advisory when a tool
|
||||
timeout is shorter than the known provider allowance.
|
||||
Setup selects the compact input-schema advertisement for new or refreshed Kimi
|
||||
registrations unless their stored configuration or setup environment explicitly
|
||||
selects `REA_MCP_INPUT_SCHEMA_PROFILE=full` or `compact`. This keeps REA's
|
||||
canonical tool validation unchanged while avoiding a Moonshot Kimi Code 2.2.0
|
||||
failure observed with the full catalog: its request was rejected because a
|
||||
single tool schema exceeded the provider's size limit. The limit is
|
||||
provider-specific and not an MCP protocol limit. `rea doctor --client kimi`
|
||||
reports an older registration with no explicit profile as stale. To restore the
|
||||
compact profile, run `rea setup --client kimi` or add
|
||||
`REA_MCP_INPUT_SCHEMA_PROFILE=compact` to the registration's `env`, then restart
|
||||
Kimi Code. An explicit `full` profile remains respected and can still exceed
|
||||
Moonshot's limit.
|
||||
The server advertises compact input schemas by default, which avoids a Moonshot
|
||||
Kimi Code 2.2.0 failure observed with the full catalog: its request was rejected
|
||||
because a single tool schema exceeded the provider's size limit. The limit is
|
||||
provider-specific and not an MCP protocol limit. Setup preserves an explicit
|
||||
`REA_MCP_INPUT_SCHEMA_PROFILE` from the stored registration or the setup
|
||||
environment; an explicit `full` profile can still exceed Moonshot's limit.
|
||||
Kimi Code also discovers personal skills in `~/.agents/skills` and project-local
|
||||
`.agents/skills`, so no separate skill root is required; setup still installs
|
||||
and verifies the matching skill files through the normal shared-skill flow.
|
||||
@@ -453,10 +447,9 @@ LM Studio does: the path stored in `~/.lmstudio-home-pointer`, otherwise
|
||||
the pointer file. LM Studio parses `mcp.json` as strict JSON, so setup rejects
|
||||
a file with comments, trailing commas, or a byte order mark without a backup
|
||||
or a write. The entry carries `command`, `args`, and `env`, and setup keeps
|
||||
every other server. Local models often have small context windows, so setup
|
||||
selects `REA_MCP_INPUT_SCHEMA_PROFILE=compact` unless the stored entry or the
|
||||
setup environment selects a profile explicitly. Doctor reports an entry with no
|
||||
explicit profile as stale, as for Kimi Code. LM Studio 0.4.26 on macOS loaded
|
||||
every other server. Local models often have small context windows; the default
|
||||
compact input-schema profile applies unless the stored entry or the setup
|
||||
environment selects `REA_MCP_INPUT_SCHEMA_PROFILE` explicitly. LM Studio 0.4.26 on macOS loaded
|
||||
this registration, and a local model called an REA tool through it. Linux and
|
||||
Windows remain unverified.
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ import { lstat, stat } from "node:fs/promises";
|
||||
import { err, ok, type Result } from "../domain/result.js";
|
||||
|
||||
import { PRODUCT_IDENTITY } from "../identity.js";
|
||||
import { snapshotEnvironment } from "../process/snapshotEnvironment.js";
|
||||
import { CURRENT_ENTRYPOINT_PATH } from "../process/CurrentEntrypointPath.js";
|
||||
import {
|
||||
MCP_STARTUP_POLICY,
|
||||
@@ -28,7 +27,6 @@ import {
|
||||
import {
|
||||
clientEvidencePaths,
|
||||
clientOwnershipEvidencePaths,
|
||||
compactInputSchemaByDefault,
|
||||
manualRegistrationRemediation,
|
||||
supportedClients,
|
||||
} from "./SupportedClients.js";
|
||||
@@ -337,15 +335,17 @@ export const readClientRegistrationInspections = async (
|
||||
continue;
|
||||
}
|
||||
const registrationEnvironment =
|
||||
compactInputSchemaByDefault(client) || client.name === "codex"
|
||||
client.name === "kimi" ||
|
||||
client.name === "codex" ||
|
||||
client.name === "lm_studio"
|
||||
? await clientRegistrationEnvironmentDetailsWithBudget(
|
||||
parsed,
|
||||
client,
|
||||
{},
|
||||
"effective",
|
||||
client.name === "kimi" || client.name === "codex"
|
||||
? options.resolveProviderRequestBudget
|
||||
: undefined,
|
||||
client.name === "lm_studio"
|
||||
? undefined
|
||||
: options.resolveProviderRequestBudget,
|
||||
options.platform,
|
||||
)
|
||||
: undefined;
|
||||
@@ -375,12 +375,6 @@ export const readClientRegistrationInspections = async (
|
||||
registration,
|
||||
client: effectiveClient,
|
||||
commandFacts,
|
||||
inputSchemaProfileSelected:
|
||||
registrationEnvironment?.ok === true &&
|
||||
snapshotEnvironment(
|
||||
registrationEnvironment.value.values,
|
||||
options.platform,
|
||||
).REA_MCP_INPUT_SCHEMA_PROFILE !== undefined,
|
||||
});
|
||||
record(
|
||||
configuredStatus(
|
||||
@@ -510,12 +504,10 @@ const registrationAligned = ({
|
||||
registration,
|
||||
client,
|
||||
commandFacts,
|
||||
inputSchemaProfileSelected,
|
||||
}: {
|
||||
readonly registration: ClientRegistration;
|
||||
readonly client: SetupClient;
|
||||
readonly commandFacts: ClientRegistrationCommandFacts;
|
||||
readonly inputSchemaProfileSelected: boolean;
|
||||
}): "aligned" | "stale" | "unknown" => {
|
||||
const { identity } = commandFacts;
|
||||
if (identity === "unknown") return "unknown";
|
||||
@@ -537,8 +529,6 @@ const registrationAligned = ({
|
||||
registration.toolTimeoutMs === undefined)
|
||||
)
|
||||
return "stale";
|
||||
if (compactInputSchemaByDefault(client) && !inputSchemaProfileSelected)
|
||||
return "stale";
|
||||
// Native transport is admitted separately; the Harness route must name REA.
|
||||
if (client.format === "dsh" && registration.serverName !== "rea")
|
||||
return "stale";
|
||||
|
||||
@@ -47,7 +47,6 @@ import {
|
||||
} from "./ClientRegistration.js";
|
||||
|
||||
import { PRODUCT_IDENTITY } from "../identity.js";
|
||||
import { snapshotEnvironment } from "../process/snapshotEnvironment.js";
|
||||
import { currentClientRegistrationCommand } from "./ClientRegistrationIdentity.js";
|
||||
import { resolveClientConfigTransactionPath } from "./ClientConfigPath.js";
|
||||
import { packageReadTargetChanged } from "./MsixPackageStorage.js";
|
||||
@@ -67,7 +66,6 @@ import type {
|
||||
SetupProviderEnvironment,
|
||||
} from "./SetupTypes.js";
|
||||
import {
|
||||
compactInputSchemaByDefault,
|
||||
registrationWriteBlocker,
|
||||
type SetupClient,
|
||||
} from "./SupportedClients.js";
|
||||
@@ -940,20 +938,11 @@ const clientConfigurationDesired = async (
|
||||
"fragment",
|
||||
);
|
||||
if (!environment.ok) throw environment.error;
|
||||
const registrationEnvironment =
|
||||
compactInputSchemaByDefault(client) &&
|
||||
snapshotEnvironment(environment.value).REA_MCP_INPUT_SCHEMA_PROFILE ===
|
||||
undefined
|
||||
? {
|
||||
...environment.value,
|
||||
REA_MCP_INPUT_SCHEMA_PROFILE: "compact",
|
||||
}
|
||||
: environment.value;
|
||||
const registration = refreshClientRegistration(
|
||||
client,
|
||||
format,
|
||||
launcher,
|
||||
registrationEnvironment,
|
||||
environment.value,
|
||||
parsed === undefined
|
||||
? undefined
|
||||
: effectiveClientServer(parsed, PRODUCT_IDENTITY.mcpServerKey),
|
||||
|
||||
@@ -190,12 +190,6 @@ const codexDirectory = ({ home, env }: ClientPathContext): string =>
|
||||
const kimiDirectory = ({ home, env }: ClientPathContext): string =>
|
||||
env.KIMI_CODE_HOME || join(home, ".kimi-code");
|
||||
|
||||
/** Clients registered with the compact input-schema profile unless one is selected. */
|
||||
export const compactInputSchemaByDefault = ({
|
||||
name,
|
||||
}: Pick<SetupClient, "name">): boolean =>
|
||||
name === "kimi" || name === "lm_studio";
|
||||
|
||||
/**
|
||||
* LM Studio's findLMStudioHome, read-only: a home pointer file wins, then an
|
||||
* existing ~/.cache/lm-studio, then ~/.lmstudio. Setup never writes the pointer.
|
||||
|
||||
@@ -136,6 +136,30 @@ describe("client registration status", () => {
|
||||
});
|
||||
|
||||
describe("client registration environment validation", () => {
|
||||
it("reports invalid LM Studio runtime settings without requiring an explicit profile", async () => {
|
||||
const home = await createTestTempDirectory("rea-lm-studio-env-");
|
||||
await mkdir(join(home, ".lmstudio"));
|
||||
await writeFile(
|
||||
join(home, ".lmstudio/mcp.json"),
|
||||
JSON.stringify({
|
||||
mcpServers: {
|
||||
rea: {
|
||||
command: "npx",
|
||||
args: ["-y", PRODUCT_IDENTITY.registrationPackageSpecifier, "mcp"],
|
||||
env: { REA_MCP_INPUT_SCHEMA_PROFILE: "invalid" },
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
const statuses = await readClientRegistrationStatuses(home, "/current/rea");
|
||||
expect(statuses).toContainEqual(
|
||||
expect.objectContaining({
|
||||
client: "lm_studio",
|
||||
state: "invalid",
|
||||
remediation: expect.stringContaining("REA_MCP_INPUT_SCHEMA_PROFILE"),
|
||||
}),
|
||||
);
|
||||
});
|
||||
it("reports an otherwise aligned registration invalid for a bad tool-family scope", async () => {
|
||||
const home = await createTestTempDirectory("rea-registration-env-");
|
||||
await mkdir(join(home, ".cursor"));
|
||||
|
||||
@@ -38,12 +38,14 @@ const exists = async (path: string): Promise<boolean> => {
|
||||
|
||||
const expectedRegistration = (
|
||||
launcher: readonly string[],
|
||||
profile = "compact",
|
||||
profile?: "full" | "compact",
|
||||
toolTimeoutMs = 450_000,
|
||||
) => ({
|
||||
command: launcher[0],
|
||||
args: launcher.slice(1),
|
||||
env: { REA_MCP_INPUT_SCHEMA_PROFILE: profile },
|
||||
...(profile === undefined
|
||||
? {}
|
||||
: { env: { REA_MCP_INPUT_SCHEMA_PROFILE: profile } }),
|
||||
startupTimeoutMs: MCP_STARTUP_POLICY.kimiStartupTimeoutMs,
|
||||
toolTimeoutMs,
|
||||
});
|
||||
@@ -318,7 +320,7 @@ describe("Kimi Code input-schema profile selection", () => {
|
||||
},
|
||||
);
|
||||
|
||||
it("reports an omitted-profile registration stale until setup adds compact", async () => {
|
||||
it("reports an omitted-profile registration aligned because compact is the server default", async () => {
|
||||
const { home, client } = await kimiClient();
|
||||
await writeFile(
|
||||
client.configPath,
|
||||
@@ -340,13 +342,13 @@ describe("Kimi Code input-schema profile selection", () => {
|
||||
environment: {},
|
||||
})
|
||||
).find(({ client: name }) => name === "kimi"),
|
||||
).toMatchObject({ state: "stale", command });
|
||||
expect(
|
||||
(await configureClientConfiguration(client, {}, command)).status,
|
||||
).toBe("configured");
|
||||
).toMatchObject({ state: "aligned", command });
|
||||
expect(await configureClientConfiguration(client, {}, command)).toEqual({
|
||||
status: "unchanged",
|
||||
});
|
||||
expect(
|
||||
JSON.parse(await readFile(client.configPath, "utf8")).mcpServers.rea,
|
||||
).toEqual(expectedRegistration(command, "compact", 120_000));
|
||||
).toEqual(expectedRegistration(command, undefined, 120_000));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -30,10 +30,12 @@ const exists = async (path: string): Promise<boolean> => {
|
||||
}
|
||||
};
|
||||
|
||||
const expectedRegistration = (profile = "compact") => ({
|
||||
const expectedRegistration = (profile?: "full" | "compact") => ({
|
||||
command: command[0],
|
||||
args: command.slice(1),
|
||||
env: { REA_MCP_INPUT_SCHEMA_PROFILE: profile },
|
||||
...(profile === undefined
|
||||
? {}
|
||||
: { env: { REA_MCP_INPUT_SCHEMA_PROFILE: profile } }),
|
||||
});
|
||||
|
||||
const doctorState = async (home: string) =>
|
||||
@@ -89,7 +91,7 @@ describe("LM Studio home resolution", () => {
|
||||
|
||||
describe("LM Studio registration lifecycle", () => {
|
||||
it.each(["default", "pointer", "cache"] as const)(
|
||||
"registers rea with the compact profile in the %s home",
|
||||
"registers rea with the default input profile in the %s home",
|
||||
async (layout) => {
|
||||
const { home, directory, client } = await installedHome(layout);
|
||||
const pointer = join(home, ".lmstudio-home-pointer");
|
||||
@@ -155,7 +157,7 @@ describe("LM Studio registration lifecycle", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps an explicit full profile and reports an omitted profile stale", async () => {
|
||||
it("keeps an explicit full profile and reports an omitted profile aligned", async () => {
|
||||
const { home, client } = await installedHome("default");
|
||||
await writeFile(
|
||||
client.configPath,
|
||||
@@ -163,7 +165,7 @@ describe("LM Studio registration lifecycle", () => {
|
||||
mcpServers: { rea: { command: command[0], args: command.slice(1) } },
|
||||
}),
|
||||
);
|
||||
expect(await doctorState(home)).toMatchObject({ state: "stale" });
|
||||
expect(await doctorState(home)).toMatchObject({ state: "aligned" });
|
||||
|
||||
expect(
|
||||
(
|
||||
|
||||
Reference in new issue
Block a user