feat(hub): register RPC handlers for hub, agent, and gateway operations
Add 5 new RPC methods (getHubInfo, listAgents, createAgent, deleteAgent, updateGateway) mirroring the existing Console HTTP API, enabling pure WebSocket communication from the frontend. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
64878d9fe1
commit
1f22c3e578
10 changed files with 283 additions and 0 deletions
130
docs/rpc.md
130
docs/rpc.md
|
|
@ -207,6 +207,136 @@ const result = await client.request<GetAgentMessagesResult>(
|
|||
}
|
||||
```
|
||||
|
||||
### `getHubInfo`
|
||||
|
||||
Returns Hub status information. No parameters required.
|
||||
|
||||
**Response:**
|
||||
|
||||
```ts
|
||||
interface GetHubInfoResult {
|
||||
hubId: string; // Hub device ID
|
||||
url: string; // Current Gateway URL
|
||||
connectionState: string; // "disconnected" | "connecting" | "connected" | "registered"
|
||||
agentCount: number; // Number of active agents
|
||||
}
|
||||
```
|
||||
|
||||
**Example:**
|
||||
|
||||
```ts
|
||||
const info = await client.request<GetHubInfoResult>(hubDeviceId, "getHubInfo");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `listAgents`
|
||||
|
||||
Lists all active agents. No parameters required.
|
||||
|
||||
**Response:**
|
||||
|
||||
```ts
|
||||
interface ListAgentsResult {
|
||||
agents: { id: string; closed: boolean }[];
|
||||
}
|
||||
```
|
||||
|
||||
**Example:**
|
||||
|
||||
```ts
|
||||
const result = await client.request<ListAgentsResult>(hubDeviceId, "listAgents");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `createAgent`
|
||||
|
||||
Creates a new agent or restores an existing one.
|
||||
|
||||
**Parameters:**
|
||||
|
||||
```ts
|
||||
interface CreateAgentParams {
|
||||
id?: string; // optional - reuse existing session ID
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```ts
|
||||
interface CreateAgentResult {
|
||||
id: string; // the created/restored agent session ID
|
||||
}
|
||||
```
|
||||
|
||||
**Example:**
|
||||
|
||||
```ts
|
||||
const result = await client.request<CreateAgentResult>(hubDeviceId, "createAgent");
|
||||
// or with specific ID:
|
||||
const result = await client.request<CreateAgentResult>(hubDeviceId, "createAgent", { id: "existing-id" });
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `deleteAgent`
|
||||
|
||||
Closes and removes an agent.
|
||||
|
||||
**Parameters:**
|
||||
|
||||
```ts
|
||||
interface DeleteAgentParams {
|
||||
id: string; // required - agent ID to delete
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```ts
|
||||
interface DeleteAgentResult {
|
||||
ok: boolean; // true if agent was found and deleted
|
||||
}
|
||||
```
|
||||
|
||||
**Example:**
|
||||
|
||||
```ts
|
||||
const result = await client.request<DeleteAgentResult>(hubDeviceId, "deleteAgent", { id: "019abc12-..." });
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `updateGateway`
|
||||
|
||||
Reconnects the Hub to a different Gateway URL.
|
||||
|
||||
**Parameters:**
|
||||
|
||||
```ts
|
||||
interface UpdateGatewayParams {
|
||||
url: string; // required - new Gateway URL
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```ts
|
||||
interface UpdateGatewayResult {
|
||||
url: string; // the new URL
|
||||
connectionState: string; // connection state after reconnect
|
||||
}
|
||||
```
|
||||
|
||||
**Example:**
|
||||
|
||||
```ts
|
||||
const result = await client.request<UpdateGatewayResult>(hubDeviceId, "updateGateway", { url: "http://localhost:4000" });
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Adding New RPC Methods
|
||||
|
||||
1. Create a handler file in `src/hub/rpc/handlers/`:
|
||||
|
|
|
|||
|
|
@ -16,6 +16,14 @@ export {
|
|||
isResponseError,
|
||||
type GetAgentMessagesParams,
|
||||
type GetAgentMessagesResult,
|
||||
type GetHubInfoResult,
|
||||
type ListAgentsResult,
|
||||
type CreateAgentParams,
|
||||
type CreateAgentResult,
|
||||
type DeleteAgentParams,
|
||||
type DeleteAgentResult,
|
||||
type UpdateGatewayParams,
|
||||
type UpdateGatewayResult,
|
||||
} from "./rpc.js";
|
||||
|
||||
export { StreamAction, type StreamPayload } from "./stream.js";
|
||||
|
|
|
|||
|
|
@ -72,3 +72,47 @@ export interface GetAgentMessagesResult {
|
|||
offset: number;
|
||||
limit: number;
|
||||
}
|
||||
|
||||
/** getHubInfo - no params needed */
|
||||
export interface GetHubInfoResult {
|
||||
hubId: string;
|
||||
url: string;
|
||||
connectionState: string;
|
||||
agentCount: number;
|
||||
}
|
||||
|
||||
/** listAgents - no params needed */
|
||||
export interface ListAgentsResult {
|
||||
agents: { id: string; closed: boolean }[];
|
||||
}
|
||||
|
||||
/** createAgent - request params */
|
||||
export interface CreateAgentParams {
|
||||
id?: string;
|
||||
}
|
||||
|
||||
/** createAgent - response payload */
|
||||
export interface CreateAgentResult {
|
||||
id: string;
|
||||
}
|
||||
|
||||
/** deleteAgent - request params */
|
||||
export interface DeleteAgentParams {
|
||||
id: string;
|
||||
}
|
||||
|
||||
/** deleteAgent - response payload */
|
||||
export interface DeleteAgentResult {
|
||||
ok: boolean;
|
||||
}
|
||||
|
||||
/** updateGateway - request params */
|
||||
export interface UpdateGatewayParams {
|
||||
url: string;
|
||||
}
|
||||
|
||||
/** updateGateway - response payload */
|
||||
export interface UpdateGatewayResult {
|
||||
url: string;
|
||||
connectionState: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,11 @@ import { getHubId } from "./hub-identity.js";
|
|||
import { loadAgentRecords, addAgentRecord, removeAgentRecord } from "./agent-store.js";
|
||||
import { RpcDispatcher, RpcError } from "./rpc/dispatcher.js";
|
||||
import { createGetAgentMessagesHandler } from "./rpc/handlers/get-agent-messages.js";
|
||||
import { createGetHubInfoHandler } from "./rpc/handlers/get-hub-info.js";
|
||||
import { createListAgentsHandler } from "./rpc/handlers/list-agents.js";
|
||||
import { createCreateAgentHandler } from "./rpc/handlers/create-agent.js";
|
||||
import { createDeleteAgentHandler } from "./rpc/handlers/delete-agent.js";
|
||||
import { createUpdateGatewayHandler } from "./rpc/handlers/update-gateway.js";
|
||||
|
||||
export class Hub {
|
||||
private readonly agents = new Map<string, AsyncAgent>();
|
||||
|
|
@ -34,6 +39,11 @@ export class Hub {
|
|||
|
||||
this.rpc = new RpcDispatcher();
|
||||
this.rpc.register("getAgentMessages", createGetAgentMessagesHandler());
|
||||
this.rpc.register("getHubInfo", createGetHubInfoHandler(this));
|
||||
this.rpc.register("listAgents", createListAgentsHandler(this));
|
||||
this.rpc.register("createAgent", createCreateAgentHandler(this));
|
||||
this.rpc.register("deleteAgent", createDeleteAgentHandler(this));
|
||||
this.rpc.register("updateGateway", createUpdateGatewayHandler(this));
|
||||
|
||||
this.client = this.createClient(this.url);
|
||||
this.client.connect();
|
||||
|
|
|
|||
13
src/hub/rpc/handlers/create-agent.ts
Normal file
13
src/hub/rpc/handlers/create-agent.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import type { RpcHandler } from "../dispatcher.js";
|
||||
|
||||
interface HubLike {
|
||||
createAgent(id?: string): { sessionId: string };
|
||||
}
|
||||
|
||||
export function createCreateAgentHandler(hub: HubLike): RpcHandler {
|
||||
return (params: unknown) => {
|
||||
const { id } = (params ?? {}) as { id?: string };
|
||||
const agent = hub.createAgent(id);
|
||||
return { id: agent.sessionId };
|
||||
};
|
||||
}
|
||||
19
src/hub/rpc/handlers/delete-agent.ts
Normal file
19
src/hub/rpc/handlers/delete-agent.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import { RpcError, type RpcHandler } from "../dispatcher.js";
|
||||
|
||||
interface HubLike {
|
||||
closeAgent(id: string): boolean;
|
||||
}
|
||||
|
||||
export function createDeleteAgentHandler(hub: HubLike): RpcHandler {
|
||||
return (params: unknown) => {
|
||||
if (!params || typeof params !== "object") {
|
||||
throw new RpcError("INVALID_PARAMS", "params must be an object");
|
||||
}
|
||||
const { id } = params as { id?: string };
|
||||
if (!id) {
|
||||
throw new RpcError("INVALID_PARAMS", "Missing required param: id");
|
||||
}
|
||||
const ok = hub.closeAgent(id);
|
||||
return { ok };
|
||||
};
|
||||
}
|
||||
17
src/hub/rpc/handlers/get-hub-info.ts
Normal file
17
src/hub/rpc/handlers/get-hub-info.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import type { RpcHandler } from "../dispatcher.js";
|
||||
|
||||
interface HubLike {
|
||||
hubId: string;
|
||||
url: string;
|
||||
connectionState: string;
|
||||
listAgents(): string[];
|
||||
}
|
||||
|
||||
export function createGetHubInfoHandler(hub: HubLike): RpcHandler {
|
||||
return () => ({
|
||||
hubId: hub.hubId,
|
||||
url: hub.url,
|
||||
connectionState: hub.connectionState,
|
||||
agentCount: hub.listAgents().length,
|
||||
});
|
||||
}
|
||||
16
src/hub/rpc/handlers/list-agents.ts
Normal file
16
src/hub/rpc/handlers/list-agents.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import type { RpcHandler } from "../dispatcher.js";
|
||||
|
||||
interface HubLike {
|
||||
listAgents(): string[];
|
||||
getAgent(id: string): { closed: boolean } | undefined;
|
||||
}
|
||||
|
||||
export function createListAgentsHandler(hub: HubLike): RpcHandler {
|
||||
return () => {
|
||||
const agents = hub.listAgents().map((id) => {
|
||||
const agent = hub.getAgent(id);
|
||||
return { id, closed: agent?.closed ?? true };
|
||||
});
|
||||
return { agents };
|
||||
};
|
||||
}
|
||||
21
src/hub/rpc/handlers/update-gateway.ts
Normal file
21
src/hub/rpc/handlers/update-gateway.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { RpcError, type RpcHandler } from "../dispatcher.js";
|
||||
|
||||
interface HubLike {
|
||||
url: string;
|
||||
connectionState: string;
|
||||
reconnect(url: string): void;
|
||||
}
|
||||
|
||||
export function createUpdateGatewayHandler(hub: HubLike): RpcHandler {
|
||||
return (params: unknown) => {
|
||||
if (!params || typeof params !== "object") {
|
||||
throw new RpcError("INVALID_PARAMS", "params must be an object");
|
||||
}
|
||||
const { url } = params as { url?: string };
|
||||
if (!url) {
|
||||
throw new RpcError("INVALID_PARAMS", "Missing required param: url");
|
||||
}
|
||||
hub.reconnect(url);
|
||||
return { url: hub.url, connectionState: hub.connectionState };
|
||||
};
|
||||
}
|
||||
|
|
@ -1,2 +1,7 @@
|
|||
export { RpcDispatcher, RpcError, type RpcHandler } from "./dispatcher.js";
|
||||
export { createGetAgentMessagesHandler } from "./handlers/get-agent-messages.js";
|
||||
export { createGetHubInfoHandler } from "./handlers/get-hub-info.js";
|
||||
export { createListAgentsHandler } from "./handlers/list-agents.js";
|
||||
export { createCreateAgentHandler } from "./handlers/create-agent.js";
|
||||
export { createDeleteAgentHandler } from "./handlers/delete-agent.js";
|
||||
export { createUpdateGatewayHandler } from "./handlers/update-gateway.js";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue