multiclaws 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -0
- package/README.zh-CN.md +36 -0
- package/dist/gateway/handlers.d.ts +3 -0
- package/dist/gateway/handlers.js +172 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +446 -0
- package/dist/infra/gateway-client.d.ts +27 -0
- package/dist/infra/gateway-client.js +136 -0
- package/dist/infra/json-store.d.ts +4 -0
- package/dist/infra/json-store.js +57 -0
- package/dist/infra/logger.d.ts +13 -0
- package/dist/infra/logger.js +18 -0
- package/dist/infra/rate-limiter.d.ts +19 -0
- package/dist/infra/rate-limiter.js +69 -0
- package/dist/infra/tailscale.d.ts +19 -0
- package/dist/infra/tailscale.js +120 -0
- package/dist/infra/telemetry.d.ts +3 -0
- package/dist/infra/telemetry.js +17 -0
- package/dist/service/a2a-adapter.d.ts +44 -0
- package/dist/service/a2a-adapter.js +208 -0
- package/dist/service/agent-profile.d.ts +13 -0
- package/dist/service/agent-profile.js +38 -0
- package/dist/service/agent-registry.d.ts +26 -0
- package/dist/service/agent-registry.js +100 -0
- package/dist/service/multiclaws-service.d.ts +88 -0
- package/dist/service/multiclaws-service.js +708 -0
- package/dist/task/tracker.d.ts +43 -0
- package/dist/task/tracker.js +186 -0
- package/dist/team/team-store.d.ts +39 -0
- package/dist/team/team-store.js +146 -0
- package/dist/types/openclaw.d.ts +86 -0
- package/dist/types/openclaw.js +2 -0
- package/openclaw.plugin.json +34 -0
- package/package.json +56 -0
- package/skills/multiclaws/SKILL.md +164 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AgentRegistry = void 0;
|
|
4
|
+
const json_store_1 = require("../infra/json-store");
|
|
5
|
+
function emptyStore() {
|
|
6
|
+
return { version: 1, agents: [] };
|
|
7
|
+
}
|
|
8
|
+
function normalizeStore(raw) {
|
|
9
|
+
if (raw.version !== 1 || !Array.isArray(raw.agents)) {
|
|
10
|
+
return emptyStore();
|
|
11
|
+
}
|
|
12
|
+
return {
|
|
13
|
+
version: 1,
|
|
14
|
+
agents: raw.agents.filter((a) => a &&
|
|
15
|
+
typeof a.url === "string" &&
|
|
16
|
+
typeof a.name === "string" &&
|
|
17
|
+
typeof a.addedAtMs === "number"),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
class AgentRegistry {
|
|
21
|
+
filePath;
|
|
22
|
+
constructor(filePath) {
|
|
23
|
+
this.filePath = filePath;
|
|
24
|
+
}
|
|
25
|
+
async readStore() {
|
|
26
|
+
const store = await (0, json_store_1.readJsonWithFallback)(this.filePath, emptyStore());
|
|
27
|
+
return normalizeStore(store);
|
|
28
|
+
}
|
|
29
|
+
async add(params) {
|
|
30
|
+
return await (0, json_store_1.withJsonLock)(this.filePath, emptyStore(), async () => {
|
|
31
|
+
const store = await this.readStore();
|
|
32
|
+
const normalizedUrl = params.url.replace(/\/+$/, "");
|
|
33
|
+
const existing = store.agents.findIndex((a) => a.url === normalizedUrl);
|
|
34
|
+
const now = Date.now();
|
|
35
|
+
const record = {
|
|
36
|
+
url: normalizedUrl,
|
|
37
|
+
name: params.name,
|
|
38
|
+
description: params.description ?? "",
|
|
39
|
+
skills: params.skills ?? [],
|
|
40
|
+
apiKey: params.apiKey,
|
|
41
|
+
addedAtMs: existing >= 0 ? store.agents[existing].addedAtMs : now,
|
|
42
|
+
lastSeenAtMs: now,
|
|
43
|
+
};
|
|
44
|
+
if (existing >= 0) {
|
|
45
|
+
store.agents[existing] = record;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
store.agents.push(record);
|
|
49
|
+
}
|
|
50
|
+
await (0, json_store_1.writeJsonAtomically)(this.filePath, store);
|
|
51
|
+
return record;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
async remove(url) {
|
|
55
|
+
return await (0, json_store_1.withJsonLock)(this.filePath, emptyStore(), async () => {
|
|
56
|
+
const store = await this.readStore();
|
|
57
|
+
const normalizedUrl = url.replace(/\/+$/, "");
|
|
58
|
+
const before = store.agents.length;
|
|
59
|
+
store.agents = store.agents.filter((a) => a.url !== normalizedUrl);
|
|
60
|
+
if (store.agents.length === before) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
await (0, json_store_1.writeJsonAtomically)(this.filePath, store);
|
|
64
|
+
return true;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
async list() {
|
|
68
|
+
const store = await this.readStore();
|
|
69
|
+
return [...store.agents].sort((a, b) => b.lastSeenAtMs - a.lastSeenAtMs);
|
|
70
|
+
}
|
|
71
|
+
async get(url) {
|
|
72
|
+
const store = await this.readStore();
|
|
73
|
+
const normalizedUrl = url.replace(/\/+$/, "");
|
|
74
|
+
return store.agents.find((a) => a.url === normalizedUrl) ?? null;
|
|
75
|
+
}
|
|
76
|
+
async updateDescription(url, description) {
|
|
77
|
+
await (0, json_store_1.withJsonLock)(this.filePath, emptyStore(), async () => {
|
|
78
|
+
const store = await this.readStore();
|
|
79
|
+
const normalizedUrl = url.replace(/\/+$/, "");
|
|
80
|
+
const agent = store.agents.find((a) => a.url === normalizedUrl);
|
|
81
|
+
if (agent) {
|
|
82
|
+
agent.description = description;
|
|
83
|
+
agent.lastSeenAtMs = Date.now();
|
|
84
|
+
await (0, json_store_1.writeJsonAtomically)(this.filePath, store);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
async updateLastSeen(url) {
|
|
89
|
+
await (0, json_store_1.withJsonLock)(this.filePath, emptyStore(), async () => {
|
|
90
|
+
const store = await this.readStore();
|
|
91
|
+
const normalizedUrl = url.replace(/\/+$/, "");
|
|
92
|
+
const agent = store.agents.find((a) => a.url === normalizedUrl);
|
|
93
|
+
if (agent) {
|
|
94
|
+
agent.lastSeenAtMs = Date.now();
|
|
95
|
+
await (0, json_store_1.writeJsonAtomically)(this.filePath, store);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
exports.AgentRegistry = AgentRegistry;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import { type AgentRecord } from "./agent-registry";
|
|
3
|
+
import { type AgentProfile } from "./agent-profile";
|
|
4
|
+
import { type TeamRecord, type TeamMember } from "../team/team-store";
|
|
5
|
+
import type { GatewayConfig } from "../infra/gateway-client";
|
|
6
|
+
export type MulticlawsServiceOptions = {
|
|
7
|
+
stateDir: string;
|
|
8
|
+
port?: number;
|
|
9
|
+
displayName?: string;
|
|
10
|
+
selfUrl?: string;
|
|
11
|
+
gatewayConfig?: GatewayConfig;
|
|
12
|
+
logger?: {
|
|
13
|
+
info: (message: string) => void;
|
|
14
|
+
warn: (message: string) => void;
|
|
15
|
+
error: (message: string) => void;
|
|
16
|
+
debug?: (message: string) => void;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export type DelegateTaskResult = {
|
|
20
|
+
taskId?: string;
|
|
21
|
+
output?: string;
|
|
22
|
+
status: string;
|
|
23
|
+
error?: string;
|
|
24
|
+
};
|
|
25
|
+
export declare class MulticlawsService extends EventEmitter {
|
|
26
|
+
private readonly options;
|
|
27
|
+
private started;
|
|
28
|
+
private httpServer;
|
|
29
|
+
private readonly agentRegistry;
|
|
30
|
+
private readonly teamStore;
|
|
31
|
+
private readonly profileStore;
|
|
32
|
+
private readonly taskTracker;
|
|
33
|
+
private agentExecutor;
|
|
34
|
+
private a2aRequestHandler;
|
|
35
|
+
private agentCard;
|
|
36
|
+
private readonly clientFactory;
|
|
37
|
+
private readonly httpRateLimiter;
|
|
38
|
+
private selfUrl;
|
|
39
|
+
private profileDescription;
|
|
40
|
+
constructor(options: MulticlawsServiceOptions);
|
|
41
|
+
start(): Promise<void>;
|
|
42
|
+
stop(): Promise<void>;
|
|
43
|
+
updateGatewayConfig(config: GatewayConfig): void;
|
|
44
|
+
listAgents(): Promise<AgentRecord[]>;
|
|
45
|
+
addAgent(params: {
|
|
46
|
+
url: string;
|
|
47
|
+
apiKey?: string;
|
|
48
|
+
}): Promise<AgentRecord>;
|
|
49
|
+
removeAgent(url: string): Promise<boolean>;
|
|
50
|
+
delegateTask(params: {
|
|
51
|
+
agentUrl: string;
|
|
52
|
+
task: string;
|
|
53
|
+
}): Promise<DelegateTaskResult>;
|
|
54
|
+
getTaskStatus(taskId: string): import("../task/tracker").TaskRecord | null;
|
|
55
|
+
getProfile(): Promise<AgentProfile>;
|
|
56
|
+
setProfile(patch: {
|
|
57
|
+
ownerName?: string;
|
|
58
|
+
bio?: string;
|
|
59
|
+
}): Promise<AgentProfile>;
|
|
60
|
+
private updateProfileDescription;
|
|
61
|
+
private getPendingReviewPath;
|
|
62
|
+
getPendingProfileReview(): Promise<{
|
|
63
|
+
pending: boolean;
|
|
64
|
+
profile?: AgentProfile;
|
|
65
|
+
message?: string;
|
|
66
|
+
}>;
|
|
67
|
+
setPendingProfileReview(): Promise<void>;
|
|
68
|
+
clearPendingProfileReview(): Promise<void>;
|
|
69
|
+
createTeam(name: string): Promise<TeamRecord>;
|
|
70
|
+
createInvite(teamId?: string): Promise<string>;
|
|
71
|
+
joinTeam(inviteCode: string): Promise<TeamRecord>;
|
|
72
|
+
leaveTeam(teamId?: string): Promise<void>;
|
|
73
|
+
listTeamMembers(teamId?: string): Promise<{
|
|
74
|
+
team: TeamRecord;
|
|
75
|
+
members: TeamMember[];
|
|
76
|
+
} | null>;
|
|
77
|
+
private mountTeamRoutes;
|
|
78
|
+
private broadcastProfileToTeams;
|
|
79
|
+
private fetchMemberDescriptions;
|
|
80
|
+
private syncTeamToRegistry;
|
|
81
|
+
private createA2AClient;
|
|
82
|
+
private processTaskResult;
|
|
83
|
+
private extractArtifactText;
|
|
84
|
+
private notifyTailscaleSetup;
|
|
85
|
+
/** Fetch with up to 2 retries and exponential backoff. */
|
|
86
|
+
private fetchWithRetry;
|
|
87
|
+
private log;
|
|
88
|
+
}
|