fix(ci): heal current main blockers

This commit is contained in:
Vincent Koc
2026-07-13 16:10:55 -07:00
parent d5a9602b41
commit b952394bd0
5 changed files with 41 additions and 50 deletions
@@ -23,7 +23,7 @@ function memberLabel(state: APIVoiceState): string | undefined {
);
}
export async function appendDiscordVoiceParticipantContext(params: {
async function appendDiscordVoiceParticipantContext(params: {
context: DiscordVoiceIngressContext | null;
client: Client;
entry: VoiceSessionEntry;
-1
View File
@@ -66,7 +66,6 @@ const rawSqliteAllowPathGroups = {
"src/infra/state-migrations.storage.ts",
"src/infra/state-migrations.cron-run-logs.ts",
"src/infra/state-migrations.debug-proxy.ts",
"src/infra/state-migrations.task-sidecar-rows.ts",
],
"shared database stores with direct DatabaseSync access": ["src/proxy-capture/store.sqlite.ts"],
"Kysely-backed stores that own a DatabaseSync boundary": [
@@ -3,7 +3,7 @@
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { expectDefined } from "@openclaw/normalization-core";
import { validateToolArguments } from "openclaw/plugin-sdk/llm";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, describe, expect, it } from "vitest";
import { getPluginToolMeta } from "../plugins/tools.js";
import {
buildBundleMcpToolsFromCatalog,
@@ -14,33 +14,11 @@ import type { McpCatalogTool } from "./agent-bundle-mcp-types.js";
import type { McpToolCatalogDiagnostic } from "./agent-bundle-mcp-types.js";
import type { SessionMcpRuntime } from "./agent-bundle-mcp-types.js";
import { applyEmbeddedAttemptToolsAllow } from "./embedded-agent-runner/run/attempt-tool-construction-plan.js";
const mcpAppMocks = vi.hoisted(() => ({ fetchMcpAppView: vi.fn() }));
vi.mock("./mcp-ui-resource.js", () => ({
fetchMcpAppView: mcpAppMocks.fetchMcpAppView,
buildMcpAppCanvasPayload: (view: {
viewId: string;
title: string;
serverName: string;
toolName: string;
uiResourceUri: string;
toolCallId?: string;
resultMetaState?: "unavailable";
}) => ({
kind: "canvas",
view: { id: view.viewId, title: view.title },
presentation: { target: "assistant_message", sandbox: "scripts" },
mcpApp: {
viewId: view.viewId,
serverName: view.serverName,
toolName: view.toolName,
uiResourceUri: view.uiResourceUri,
...(view.toolCallId ? { toolCallId: view.toolCallId } : {}),
...(view.resultMetaState ? { resultMetaState: view.resultMetaState } : {}),
},
}),
}));
import {
getMcpAppViewLease,
MCP_APP_RESOURCE_MIME_TYPE,
testing as mcpUiResourceTesting,
} from "./mcp-ui-resource.js";
function expectTextContentBlock(block: unknown, text: string) {
const content = block as { type?: string; text?: string } | undefined;
@@ -114,8 +92,8 @@ function makeToolRuntime(
}
describe("createBundleMcpToolRuntime", () => {
beforeEach(() => {
mcpAppMocks.fetchMcpAppView.mockReset();
afterEach(() => {
mcpUiResourceTesting.clearViewStore();
});
it("keeps app-only MCP tools out of the model tool catalog", async () => {
@@ -164,14 +142,6 @@ describe("createBundleMcpToolRuntime", () => {
});
it("attaches app previews without converting typed image results to text", async () => {
mcpAppMocks.fetchMcpAppView.mockResolvedValue({
viewId: "cv_app",
title: "Demo UI",
serverName: "demo",
toolName: "show",
uiResourceUri: "ui://demo/app",
toolCallId: "call-1",
});
const tool: McpCatalogTool = {
serverName: "demo",
safeServerName: "demo",
@@ -189,6 +159,15 @@ describe("createBundleMcpToolRuntime", () => {
},
});
sessionRuntime.mcpAppsEnabled = true;
sessionRuntime.readResource = async () => ({
contents: [
{
uri: "ui://demo/app",
mimeType: MCP_APP_RESOURCE_MIME_TYPE,
text: "<html>demo</html>",
},
],
});
const materialized = await materializeBundleMcpToolsForRun({ runtime: sessionRuntime });
materialized.restrictAppTools?.(materialized.tools);
@@ -200,7 +179,7 @@ describe("createBundleMcpToolRuntime", () => {
expect(result.details).toMatchObject({
mcpAppPreview: {
mcpApp: {
viewId: "cv_app",
viewId: expect.stringMatching(/^mcp-app-/u),
serverName: "demo",
toolName: "show",
uiResourceUri: "ui://demo/app",
@@ -209,12 +188,14 @@ describe("createBundleMcpToolRuntime", () => {
},
},
});
expect(mcpAppMocks.fetchMcpAppView).toHaveBeenCalledWith(
expect.objectContaining({
toolCallId: "call-1",
allowedAppToolNames: new Set(["show"]),
}),
);
const viewId = (result.details as { mcpAppPreview?: { mcpApp?: { viewId?: string } } })
.mcpAppPreview?.mcpApp?.viewId;
expect(
getMcpAppViewLease(
expectDefined(viewId, "MCP App preview view id test invariant"),
sessionRuntime,
)?.allowedAppToolNames,
).toEqual(new Set(["show"]));
});
it("materializes bundle MCP tools and executes them", async () => {
@@ -20,7 +20,7 @@ type BeforeAgentRunSession = {
agent: { state: { messages: AgentMessage[] } };
};
export type BeforeAgentRunBlockOutcome = {
type BeforeAgentRunBlockOutcome = {
blockedBy: string;
promptError: Error;
};
+13 -2
View File
@@ -11,6 +11,7 @@ import { resetConfigRuntimeState } from "../config/config.js";
import { loadCronStore, saveCronStore } from "../cron/store.js";
import type { GuardedFetchOptions } from "../infra/net/fetch-guard.js";
import { peekSystemEvents } from "../infra/system-events.js";
import { getGatewayProcessInstanceId } from "./process-instance.js";
import type { GatewayCronState } from "./server-cron.js";
import {
connectOk,
@@ -1540,7 +1541,12 @@ describe("gateway server cron", () => {
const secondRunRes = await rpcReq(ws, "cron.run", { id: "busy-job", mode: "force" }, 1_000);
expect(secondRunRes.ok).toBe(true);
expect(secondRunRes.payload).toEqual({ ok: true, ran: false, reason: "already-running" });
expect(secondRunRes.payload).toEqual({
ok: true,
ran: false,
reason: "already-running",
processInstanceId: getGatewayProcessInstanceId(),
});
expect(cronIsolatedRun).toHaveBeenCalledTimes(1);
const finishedRun = waitForCronEvent(
@@ -1585,7 +1591,12 @@ describe("gateway server cron", () => {
try {
const runRes = await rpcReq(ws, "cron.run", { id: "future-job", mode: "due" }, 1_000);
expect(runRes.ok).toBe(true);
expect(runRes.payload).toEqual({ ok: true, ran: false, reason: "not-due" });
expect(runRes.payload).toEqual({
ok: true,
ran: false,
reason: "not-due",
processInstanceId: getGatewayProcessInstanceId(),
});
expect(cronIsolatedRun).not.toHaveBeenCalled();
} finally {
await cleanupCronTestRun({ ws, server, prevSkipCron });