
























@@ -390,6 +390,23 @@ function expectSpawnedSessionLookupCalls(spawnedBy: string) {
390390expect(callGatewayMock).toHaveBeenNthCalledWith(2, expectedCall);
391391}
392392393+function expectRecordFields(record: unknown, expected: Record<string, unknown>) {
394+expect(record).toBeDefined();
395+const actual = record as Record<string, unknown>;
396+for (const [key, value] of Object.entries(expected)) {
397+expect(actual[key]).toEqual(value);
398+}
399+return actual;
400+}
401+402+function mockCallArg(mock: ReturnType<typeof vi.fn>, callIndex = 0, argIndex = 0) {
403+const call = mock.mock.calls[callIndex];
404+if (!call) {
405+throw new Error(`Expected mock call ${callIndex}`);
406+}
407+return call[argIndex];
408+}
409+393410function getSessionStatusTool(
394411agentSessionKey = "main",
395412options?: { sandboxed?: boolean; activeModelProvider?: string; activeModelId?: string },
@@ -440,11 +457,7 @@ describe("session_status tool", () => {
440457441458await tool.execute("call-transcript-usage", {});
442459443-expect(buildStatusMessageMock).toHaveBeenCalledWith(
444-expect.objectContaining({
445-includeTranscriptUsage: true,
446-}),
447-);
460+expectRecordFields(mockCallArg(buildStatusMessageMock), { includeTranscriptUsage: true });
448461});
449462450463it("passes spawned workspace to session_status auth labels", async () => {
@@ -462,11 +475,9 @@ describe("session_status tool", () => {
462475463476await tool.execute("call-spawned-workspace-status", {});
464477465-expect(buildStatusMessageMock).toHaveBeenCalledWith(
466-expect.objectContaining({
467-workspaceDir: "/tmp/openclaw-spawned-workspace",
468-}),
469-);
478+expectRecordFields(mockCallArg(buildStatusMessageMock), {
479+workspaceDir: "/tmp/openclaw-spawned-workspace",
480+});
470481});
471482472483it("errors for unknown session keys", async () => {
@@ -698,23 +709,14 @@ describe("session_status tool", () => {
698709expect(details.ok).toBe(true);
699710expect(details.sessionKey).toBe("agent:main:current");
700711701-expect(buildStatusMessageMock).toHaveBeenCalledWith(
702-expect.objectContaining({
703-sessionEntry: expect.objectContaining({
704-providerOverride: "anthropic",
705-modelOverride: "claude-sonnet-4-6",
706-}),
707-}),
708-);
709-expect(buildStatusMessageMock).not.toHaveBeenCalledWith(
710-expect.objectContaining({
711-agent: expect.objectContaining({
712-model: expect.objectContaining({
713-primary: "openai-codex/gpt-5.2",
714-}),
715-}),
716-}),
717-);
712+const statusArg = mockCallArg(buildStatusMessageMock) as Record<string, unknown>;
713+expectRecordFields(statusArg.sessionEntry, {
714+providerOverride: "anthropic",
715+modelOverride: "claude-sonnet-4-6",
716+});
717+const agent = statusArg.agent as Record<string, unknown>;
718+const model = agent.model as Record<string, unknown>;
719+expect(model.primary).not.toBe("openai-codex/gpt-5.2");
718720});
719721720722it("resolves sessionKey=current for a channel-plugin requester via implicit fallback", async () => {
@@ -745,12 +747,12 @@ describe("session_status tool", () => {
745747expect(details.sessionKey).toBe("agent:main:telegram:group:-5096326138");
746748expect(details.statusText).toContain("OpenClaw");
747749expect(details.statusText).toContain("🧠 Model:");
748-expect(callGatewayMock).not.toHaveBeenCalledWith(
749-expect.objectContaining({
750-method: "sessions.resolve",
751-params: expect.objectContaining({ key: "current" }),
750+expect(
751+callGatewayMock.mock.calls.some(([arg]) => {
752+const request = arg as { method?: string; params?: { key?: string } };
753+return request.method === "sessions.resolve" && request.params?.key === "current";
752754}),
753-);
755+).toBe(false);
754756});
755757756758it("resolves the default session_status lookup for a channel-plugin requester via implicit fallback", async () => {
@@ -781,15 +783,9 @@ describe("session_status tool", () => {
781783782784await tool.execute("call-current-active-model", { sessionKey: "current" });
783785784-expect(buildStatusMessageMock).toHaveBeenCalledWith(
785-expect.objectContaining({
786-agent: expect.objectContaining({
787-model: expect.objectContaining({
788-primary: "openai-codex/gpt-5.2",
789-}),
790-}),
791-}),
792-);
786+const statusArg = mockCallArg(buildStatusMessageMock) as Record<string, unknown>;
787+const agent = statusArg.agent as Record<string, unknown>;
788+expectRecordFields(agent.model, { primary: "openai-codex/gpt-5.2" });
793789});
794790795791it("renders the active run model for omitted sessionKey lookups", async () => {
@@ -807,15 +803,9 @@ describe("session_status tool", () => {
807803808804await tool.execute("call-implicit-current-active-model", {});
809805810-expect(buildStatusMessageMock).toHaveBeenCalledWith(
811-expect.objectContaining({
812-agent: expect.objectContaining({
813-model: expect.objectContaining({
814-primary: "openai-codex/gpt-5.2",
815-}),
816-}),
817-}),
818-);
806+const statusArg = mockCallArg(buildStatusMessageMock) as Record<string, unknown>;
807+const agent = statusArg.agent as Record<string, unknown>;
808+expectRecordFields(agent.model, { primary: "openai-codex/gpt-5.2" });
819809});
820810821811it("renders the active run model for current lookups with persisted overrides", async () => {
@@ -835,19 +825,12 @@ describe("session_status tool", () => {
835825836826await tool.execute("call-current-active-model-with-override", { sessionKey: "current" });
837827838-expect(buildStatusMessageMock).toHaveBeenCalledWith(
839-expect.objectContaining({
840-sessionEntry: expect.not.objectContaining({
841-providerOverride: expect.any(String),
842-modelOverride: expect.any(String),
843-}),
844-agent: expect.objectContaining({
845-model: expect.objectContaining({
846-primary: "openai-codex/gpt-5.2",
847-}),
848-}),
849-}),
850-);
828+const statusArg = mockCallArg(buildStatusMessageMock) as Record<string, unknown>;
829+const sessionEntry = statusArg.sessionEntry as Record<string, unknown>;
830+expect(sessionEntry.providerOverride).toBeUndefined();
831+expect(sessionEntry.modelOverride).toBeUndefined();
832+const agent = statusArg.agent as Record<string, unknown>;
833+expectRecordFields(agent.model, { primary: "openai-codex/gpt-5.2" });
851834});
852835853836it("does not reuse the active run model after a semantic current reset", async () => {
@@ -870,15 +853,9 @@ describe("session_status tool", () => {
870853model: "default",
871854});
872855873-expect(buildStatusMessageMock).toHaveBeenCalledWith(
874-expect.objectContaining({
875-agent: expect.objectContaining({
876-model: expect.objectContaining({
877-primary: "openai/gpt-5.4",
878-}),
879-}),
880-}),
881-);
856+const statusArg = mockCallArg(buildStatusMessageMock) as Record<string, unknown>;
857+const agent = statusArg.agent as Record<string, unknown>;
858+expectRecordFields(agent.model, { primary: "openai/gpt-5.4" });
882859});
883860884861it("materializes a valid persisted session entry when implicit current fallback mutates model state", async () => {
@@ -908,13 +885,11 @@ describe("session_status tool", () => {
908885Record<string, SessionEntry>,
909886];
910887const saved = savedStore["agent:main:scope:scopy:direct:scopy"];
911-expect(saved).toEqual(
912-expect.objectContaining({
913-providerOverride: "anthropic",
914-modelOverride: "claude-sonnet-4-6",
915-liveModelSwitchPending: true,
916-}),
917-);
888+expectRecordFields(saved, {
889+providerOverride: "anthropic",
890+modelOverride: "claude-sonnet-4-6",
891+liveModelSwitchPending: true,
892+});
918893expect(saved.sessionId).toBeTypeOf("string");
919894expect(saved.sessionId.trim().length).toBeGreaterThan(0);
920895});
@@ -936,13 +911,11 @@ describe("session_status tool", () => {
936911Record<string, SessionEntry>,
937912];
938913const saved = savedStore["agent:main:scope:scopy:direct:scopy"];
939-expect(saved).toEqual(
940-expect.objectContaining({
941-providerOverride: "anthropic",
942-modelOverride: "claude-sonnet-4-6",
943-liveModelSwitchPending: true,
944-}),
945-);
914+expectRecordFields(saved, {
915+providerOverride: "anthropic",
916+modelOverride: "claude-sonnet-4-6",
917+liveModelSwitchPending: true,
918+});
946919expect(saved.sessionId).toBeTypeOf("string");
947920expect(saved.sessionId.trim().length).toBeGreaterThan(0);
948921});
@@ -1202,15 +1175,12 @@ describe("session_status tool", () => {
12021175const details = result.details as { ok?: boolean; sessionKey?: string };
12031176expect(details.ok).toBe(true);
12041177expect(details.sessionKey).toBe("agent:main:subagent:child");
1205-expect(updateSessionStoreMock).toHaveBeenCalledWith(
1206-"/tmp/main/sessions.json",
1207-expect.objectContaining({
1208-"agent:main:subagent:child": expect.objectContaining({
1209-liveModelSwitchPending: true,
1210-modelOverride: "claude-sonnet-4-6",
1211-}),
1212-}),
1213-);
1178+expect(mockCallArg(updateSessionStoreMock)).toBe("/tmp/main/sessions.json");
1179+const savedStore = mockCallArg(updateSessionStoreMock, 0, 1) as Record<string, unknown>;
1180+expectRecordFields(savedStore["agent:main:subagent:child"], {
1181+liveModelSwitchPending: true,
1182+modelOverride: "claude-sonnet-4-6",
1183+});
12141184});
1215118512161186it("uses the runtime session model as the selected card model when no override is set", async () => {
@@ -1227,15 +1197,9 @@ describe("session_status tool", () => {
1227119712281198await tool.execute("call-runtime-model", {});
122911991230-expect(buildStatusMessageMock).toHaveBeenCalledWith(
1231-expect.objectContaining({
1232-agent: expect.objectContaining({
1233-model: expect.objectContaining({
1234-primary: "anthropic/claude-opus-4-6",
1235-}),
1236-}),
1237-}),
1238-);
1200+const statusArg = mockCallArg(buildStatusMessageMock) as Record<string, unknown>;
1201+const agent = statusArg.agent as Record<string, unknown>;
1202+expectRecordFields(agent.model, { primary: "anthropic/claude-opus-4-6" });
12391203});
1240120412411205it("infers configured custom providers for runtime-only models in session_status", async () => {
@@ -1274,16 +1238,10 @@ describe("session_status tool", () => {
1274123812751239await tool.execute("call-runtime-custom-provider", {});
127612401277-expect(buildStatusMessageMock).toHaveBeenCalledWith(
1278-expect.objectContaining({
1279-agent: expect.objectContaining({
1280-model: expect.objectContaining({
1281-primary: "qwen-dashscope/qwen-max",
1282-}),
1283-}),
1284-modelAuth: "api-key (models.json)",
1285-}),
1286-);
1241+const statusArg = mockCallArg(buildStatusMessageMock) as Record<string, unknown>;
1242+const agent = statusArg.agent as Record<string, unknown>;
1243+expectRecordFields(agent.model, { primary: "qwen-dashscope/qwen-max" });
1244+expect(statusArg.modelAuth).toBe("api-key (models.json)");
12871245});
1288124612891247it("preserves an unknown runtime provider in the selected status card model", async () => {
@@ -1299,20 +1257,14 @@ describe("session_status tool", () => {
1299125713001258await tool.execute("call-legacy-runtime-model", {});
130112591302-expect(buildStatusMessageMock).toHaveBeenCalledWith(
1303-expect.objectContaining({
1304-agent: expect.objectContaining({
1305-model: expect.objectContaining({
1306-primary: "legacy-runtime-model",
1307-}),
1308-}),
1309-sessionEntry: expect.objectContaining({
1310-model: "legacy-runtime-model",
1311-providerOverride: "",
1312-}),
1313-modelAuth: undefined,
1314-}),
1315-);
1260+const statusArg = mockCallArg(buildStatusMessageMock) as Record<string, unknown>;
1261+const agent = statusArg.agent as Record<string, unknown>;
1262+expectRecordFields(agent.model, { primary: "legacy-runtime-model" });
1263+expectRecordFields(statusArg.sessionEntry, {
1264+model: "legacy-runtime-model",
1265+providerOverride: "",
1266+});
1267+expect(statusArg.modelAuth).toBeUndefined();
13161268});
1317126913181270it("passes per-agent thinkingDefault through to the status card", async () => {
@@ -1348,14 +1300,9 @@ describe("session_status tool", () => {
1348130013491301await tool.execute("call-agent-thinking", {});
135013021351-expect(buildStatusMessageMock).toHaveBeenCalledWith(
1352-expect.objectContaining({
1353-agentId: "kira",
1354-agent: expect.objectContaining({
1355-thinkingDefault: "xhigh",
1356-}),
1357-}),
1358-);
1303+const statusArg = mockCallArg(buildStatusMessageMock) as Record<string, unknown>;
1304+expect(statusArg.agentId).toBe("kira");
1305+expectRecordFields(statusArg.agent, { thinkingDefault: "xhigh" });
13591306} finally {
13601307mockConfig = savedConfig;
13611308}
@@ -1393,14 +1340,9 @@ describe("session_status tool", () => {
1393134013941341await tool.execute("call-agent-thinking-implicit", {});
139513421396-expect(buildStatusMessageMock).toHaveBeenCalledWith(
1397-expect.objectContaining({
1398-agentId: "kira",
1399-agent: expect.objectContaining({
1400-thinkingDefault: "medium",
1401-}),
1402-}),
1403-);
1343+const statusArg = mockCallArg(buildStatusMessageMock) as Record<string, unknown>;
1344+expect(statusArg.agentId).toBe("kira");
1345+expectRecordFields(statusArg.agent, { thinkingDefault: "medium" });
14041346} finally {
14051347mockConfig = savedConfig;
14061348}
@@ -1446,14 +1388,9 @@ describe("session_status tool", () => {
1446138814471389await tool.execute("call-agent-thinking-runtime-hydration", {});
144813901449-expect(buildStatusMessageMock).toHaveBeenCalledWith(
1450-expect.objectContaining({
1451-agentId: "kira",
1452-agent: expect.objectContaining({
1453-thinkingDefault: "medium",
1454-}),
1455-}),
1456-);
1391+const statusArg = mockCallArg(buildStatusMessageMock) as Record<string, unknown>;
1392+expect(statusArg.agentId).toBe("kira");
1393+expectRecordFields(statusArg.agent, { thinkingDefault: "medium" });
14571394} finally {
14581395mockConfig = savedConfig;
14591396}
@@ -1472,14 +1409,9 @@ describe("session_status tool", () => {
1472140914731410await tool.execute("call-origin-provider", {});
147414111475-expect(resolveQueueSettingsMock).toHaveBeenCalledWith(
1476-expect.objectContaining({
1477-channel: "quietchat",
1478-sessionEntry: expect.objectContaining({
1479-origin: { provider: "quietchat" },
1480-}),
1481-}),
1482-);
1412+const queueArg = mockCallArg(resolveQueueSettingsMock) as Record<string, unknown>;
1413+expect(queueArg.channel).toBe("quietchat");
1414+expectRecordFields(queueArg.sessionEntry, { origin: { provider: "quietchat" } });
14831415});
1484141614851417it("resolves sessionId inputs", async () => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。