























@@ -6,8 +6,24 @@ const toolState = vi.hoisted(() => ({
66tools: [] as AnyAgentTool[],
77pluginIds: {} as Record<string, string | undefined>,
88throwError: null as Error | null,
9+runtimeModel: null as {
10+id: string;
11+name: string;
12+provider: string;
13+api: string;
14+contextWindow?: number;
15+compat?: Record<string, unknown>;
16+} | null,
17+resolveModelError: null as Error | null,
18+resolveModel: vi.fn(),
919createTools: vi.fn<typeof createOpenClawCodingTools>(),
10-normalizeTools: vi.fn((options: { tools: AnyAgentTool[] }) => options.tools),
20+normalizeTools: vi.fn(
21+(options: { tools: AnyAgentTool[]; modelApi?: string; model?: unknown }) => options.tools,
22+),
23+}));
24+25+vi.mock("../../../agents/embedded-agent-runner/model.js", () => ({
26+resolveModel: (...args: unknown[]) => toolState.resolveModel(...args),
1127}));
12281329vi.mock("../../../agents/agent-tools.js", () => ({
@@ -50,6 +66,18 @@ describe("active tool schema doctor warnings", () => {
5066toolState.tools = [];
5167toolState.pluginIds = {};
5268toolState.throwError = null;
69+toolState.runtimeModel = null;
70+toolState.resolveModelError = null;
71+toolState.resolveModel.mockReset().mockImplementation(() => {
72+if (toolState.resolveModelError) {
73+throw toolState.resolveModelError;
74+}
75+return {
76+model: toolState.runtimeModel,
77+authStorage: {},
78+modelRegistry: {},
79+};
80+});
5381toolState.createTools.mockClear();
5482toolState.normalizeTools.mockReset().mockImplementation((options) => options.tools);
5583});
@@ -94,10 +122,25 @@ describe("active tool schema doctor warnings", () => {
94122it("validates provider-normalized runtime schemas before reporting doctor health", () => {
95123const healthyTool = tool("message", { type: "object", properties: {} });
96124const dynamicTool = tool("dofbot_move_angles", { type: "object", properties: {} });
125+toolState.runtimeModel = {
126+id: "gpt-5.5",
127+name: "GPT-5.5",
128+provider: "openai",
129+api: "openai-responses",
130+contextWindow: 400_000,
131+compat: { unsupportedToolSchemaKeywords: ["$dynamicRef"] },
132+};
97133toolState.tools = [healthyTool, dynamicTool];
98134toolState.pluginIds = { dofbot_move_angles: "dofbot" };
99-toolState.normalizeTools.mockImplementation(({ tools }) =>
100-tools.map((entry) =>
135+toolState.normalizeTools.mockImplementation(({ tools, modelApi, model }) => {
136+if (
137+modelApi !== "openai-responses" ||
138+!model ||
139+(model as { id?: string }).id !== "gpt-5.5"
140+) {
141+return tools;
142+}
143+return tools.map((entry) =>
101144entry.name === "dofbot_move_angles"
102145 ? tool("dofbot_move_angles", {
103146type: "object",
@@ -106,12 +149,17 @@ describe("active tool schema doctor warnings", () => {
106149},
107150})
108151 : entry,
109-),
110-);
152+);
153+});
111154112155expect(
113156collectActiveToolSchemaProjectionWarnings({
114157cfg: {
158+agents: {
159+defaults: {
160+model: { primary: "openai/gpt-5.5" },
161+},
162+},
115163plugins: {
116164entries: {
117165dofbot: { enabled: true },
@@ -123,6 +171,19 @@ describe("active tool schema doctor warnings", () => {
123171).toEqual([
124172'- agents.main: active tool "dofbot_move_angles" from plugin "dofbot" has unsupported runtime input schema (dofbot_move_angles.parameters.properties.target.$dynamicRef). OpenClaw will quarantine this tool at runtime; fix or disable the plugin, or remove the tool from active allowlists.',
125173]);
174+expect(toolState.createTools).toHaveBeenCalledWith(
175+expect.objectContaining({
176+modelApi: "openai-responses",
177+modelCompat: { unsupportedToolSchemaKeywords: ["$dynamicRef"] },
178+modelContextWindowTokens: 400_000,
179+}),
180+);
181+expect(toolState.normalizeTools).toHaveBeenCalledWith(
182+expect.objectContaining({
183+modelApi: "openai-responses",
184+model: expect.objectContaining({ id: "gpt-5.5", api: "openai-responses" }),
185+}),
186+);
126187});
127188128189it("reports runtime schema normalization failures instead of crashing doctor", () => {
@@ -141,6 +202,22 @@ describe("active tool schema doctor warnings", () => {
141202]);
142203});
143204205+it("reports runtime model context failures instead of crashing doctor", () => {
206+toolState.resolveModelError = new Error("provider model hook failed");
207+toolState.tools = [tool("message", { type: "object", properties: {} })];
208+209+expect(
210+collectActiveToolSchemaProjectionWarnings({
211+cfg: {},
212+env: { HOME: "/tmp/openclaw-test" },
213+}),
214+).toEqual([
215+"- agents.main: active tool schema validation could not resolve the runtime model context (provider model hook failed). Fix provider/model loading errors before relying on assistant tool startup.",
216+]);
217+expect(toolState.createTools).toHaveBeenCalled();
218+expect(toolState.normalizeTools).toHaveBeenCalled();
219+});
220+144221it("reports toolset construction failures instead of crashing doctor", () => {
145222toolState.throwError = new Error("plugin startup failed");
146223此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。