fix(sdk): list helpers work without filters

SDK list helpers now send an empty params object when filters are omitted while preserving explicit invalid params for Gateway validation.\n\nVerification:\n- git diff --check origin/main...HEAD\n- node --check packages/sdk/src/client.ts\n- codex review --base origin/main\n- GitHub Actions CI release gate 27855603923 succeeded on 353f13c0d1
This commit is contained in:
Vincent Koc
2026-06-20 09:22:48 +08:00
committed by GitHub
parent 9491e9187d
commit d76c1daa52
3 changed files with 79 additions and 8 deletions
+7 -7
View File
@@ -708,7 +708,7 @@ export class AgentsNamespace {
constructor(private readonly client: OpenClaw) {}
async list(params?: Record<string, unknown>): Promise<unknown> {
return await this.client.request("agents.list", params);
return await this.client.request("agents.list", params === undefined ? {} : params);
}
async get(id: string): Promise<Agent> {
@@ -733,7 +733,7 @@ export class SessionsNamespace {
constructor(private readonly client: OpenClaw) {}
async list(params?: Record<string, unknown>): Promise<unknown> {
return await this.client.request("sessions.list", params);
return await this.client.request("sessions.list", params === undefined ? {} : params);
}
async create(params: SessionCreateParams = {}): Promise<Session> {
@@ -817,7 +817,7 @@ export class TasksNamespace extends RpcNamespace {
}
async list(params?: TasksListParams): Promise<TasksListResult> {
return await this.call("list", params);
return await this.call("list", params === undefined ? {} : params);
}
async get(taskId: string): Promise<TasksGetResult> {
@@ -839,7 +839,7 @@ export class ModelsNamespace extends RpcNamespace {
}
async list(params?: unknown): Promise<unknown> {
return await this.call("list", params);
return await this.call("list", params === undefined ? {} : params);
}
async status(params?: unknown): Promise<unknown> {
@@ -854,7 +854,7 @@ export class ToolsNamespace extends RpcNamespace {
}
async list(params?: unknown): Promise<unknown> {
return await this.call("catalog", params);
return await this.call("catalog", params === undefined ? {} : params);
}
async effective(params?: unknown): Promise<unknown> {
@@ -903,7 +903,7 @@ export class ApprovalsNamespace {
constructor(private readonly client: OpenClaw) {}
async list(params?: unknown): Promise<unknown> {
return await this.client.request("exec.approval.list", params);
return await this.client.request("exec.approval.list", params === undefined ? {} : params);
}
async respond(approvalId: string, decision: Record<string, unknown>): Promise<unknown> {
@@ -918,7 +918,7 @@ export class EnvironmentsNamespace extends RpcNamespace {
}
async list(params?: unknown): Promise<EnvironmentsListResult> {
return await this.call("list", params ?? {});
return await this.call("list", params === undefined ? {} : params);
}
async create(params?: unknown): Promise<unknown> {
+8
View File
@@ -538,6 +538,14 @@ describe("OpenClaw SDK websocket e2e", () => {
"exec.approval.list",
"exec.approval.resolve",
]);
const requestParams = new Map(
gateway.requests.map((request) => [request.method, request.params]),
);
expect(requestParams.get("agents.list")).toEqual({});
expect(requestParams.get("sessions.list")).toEqual({});
expect(requestParams.get("models.list")).toEqual({});
expect(requestParams.get("tools.catalog")).toEqual({});
expect(requestParams.get("exec.approval.list")).toEqual({});
} finally {
await oc.close();
await gateway.close();
+64 -1
View File
@@ -676,6 +676,69 @@ describe("OpenClaw SDK", () => {
]);
});
it("sends empty params for no-arg Gateway list helpers", async () => {
const transport = new FakeTransport({
"agents.list": { agents: [] },
"sessions.list": { sessions: [] },
"tasks.list": { tasks: [] },
"models.list": { models: [] },
"tools.catalog": { tools: [] },
"exec.approval.list": { approvals: [] },
"environments.list": { environments: [] },
});
const oc = new OpenClaw({ transport });
await expect(oc.agents.list()).resolves.toEqual({ agents: [] });
await expect(oc.sessions.list()).resolves.toEqual({ sessions: [] });
await expect(oc.tasks.list()).resolves.toEqual({ tasks: [] });
await expect(oc.models.list()).resolves.toEqual({ models: [] });
await expect(oc.tools.list()).resolves.toEqual({ tools: [] });
await expect(oc.approvals.list()).resolves.toEqual({ approvals: [] });
await expect(oc.environments.list()).resolves.toEqual({ environments: [] });
expect(transport.calls).toEqual([
{ method: "agents.list", params: {}, options: undefined },
{ method: "sessions.list", params: {}, options: undefined },
{ method: "tasks.list", params: {}, options: undefined },
{ method: "models.list", params: {}, options: undefined },
{ method: "tools.catalog", params: {}, options: undefined },
{ method: "exec.approval.list", params: {}, options: undefined },
{ method: "environments.list", params: {}, options: undefined },
]);
});
it("preserves explicit null params for Gateway list validation", async () => {
type ListMethod = (this: unknown, params: unknown) => Promise<unknown>;
const transport = new FakeTransport({
"agents.list": { agents: [] },
"sessions.list": { sessions: [] },
"tasks.list": { tasks: [] },
"models.list": { models: [] },
"tools.catalog": { tools: [] },
"exec.approval.list": { approvals: [] },
"environments.list": { environments: [] },
});
const oc = new OpenClaw({ transport });
await (oc.agents.list as unknown as ListMethod).call(oc.agents, null);
await (oc.sessions.list as unknown as ListMethod).call(oc.sessions, null);
await (oc.tasks.list as unknown as ListMethod).call(oc.tasks, null);
await oc.models.list(null);
await oc.tools.list(null);
await oc.approvals.list(null);
await oc.environments.list(null);
expect(transport.calls).toEqual([
{ method: "agents.list", params: null, options: undefined },
{ method: "sessions.list", params: null, options: undefined },
{ method: "tasks.list", params: null, options: undefined },
{ method: "models.list", params: null, options: undefined },
{ method: "tools.catalog", params: null, options: undefined },
{ method: "exec.approval.list", params: null, options: undefined },
{ method: "environments.list", params: null, options: undefined },
]);
});
it("keeps close terminal when it races a pending connect", async () => {
const transport = new DelayedConnectTransport({
"agents.list": { agents: [] },
@@ -713,7 +776,7 @@ describe("OpenClaw SDK", () => {
{
method: "exec.approval.list",
options: undefined,
params: undefined,
params: {},
},
{
method: "exec.approval.resolve",