@agentmesh-p2p/sdk 0.0.0-stage → 0.1.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 +182 -2
- package/dist/auth.d.ts +66 -0
- package/dist/auth.js +164 -0
- package/dist/authorizer.d.ts +41 -0
- package/dist/authorizer.js +201 -0
- package/dist/base58.d.ts +2 -0
- package/dist/base58.js +57 -0
- package/dist/biscuit.d.ts +75 -0
- package/dist/biscuit.js +250 -0
- package/dist/bytes.d.ts +10 -0
- package/dist/bytes.js +51 -0
- package/dist/challenges.d.ts +16 -0
- package/dist/challenges.js +55 -0
- package/dist/conformance-join.d.ts +1 -0
- package/dist/conformance-join.js +257 -0
- package/dist/conformance.d.ts +1 -0
- package/dist/conformance.js +60 -0
- package/dist/controlplane.d.ts +123 -0
- package/dist/controlplane.js +368 -0
- package/dist/credential.d.ts +66 -0
- package/dist/credential.js +124 -0
- package/dist/discovery.d.ts +50 -0
- package/dist/discovery.js +150 -0
- package/dist/gen/agentmesh_pb.d.ts +2740 -0
- package/dist/gen/agentmesh_pb.js +591 -0
- package/dist/gen/datalog.d.ts +39 -0
- package/dist/gen/datalog.js +84 -0
- package/dist/host.d.ts +47 -0
- package/dist/host.js +109 -0
- package/dist/http1.d.ts +68 -0
- package/dist/http1.js +371 -0
- package/dist/identity.d.ts +31 -0
- package/dist/identity.js +125 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +30 -0
- package/dist/libp2p-http-node.d.ts +17 -0
- package/dist/libp2p-http-node.js +116 -0
- package/dist/libp2p-http.d.ts +165 -0
- package/dist/libp2p-http.js +581 -0
- package/dist/mcp.d.ts +67 -0
- package/dist/mcp.js +157 -0
- package/dist/mesh.d.ts +151 -0
- package/dist/mesh.js +370 -0
- package/dist/platform/ingress.browser.d.ts +1 -0
- package/dist/platform/ingress.browser.js +16 -0
- package/dist/platform/ingress.d.ts +1 -0
- package/dist/platform/ingress.js +15 -0
- package/dist/platform/state.browser.d.ts +5 -0
- package/dist/platform/state.browser.js +47 -0
- package/dist/platform/state.d.ts +5 -0
- package/dist/platform/state.js +44 -0
- package/dist/platform/transports.browser.d.ts +3 -0
- package/dist/platform/transports.browser.js +27 -0
- package/dist/platform/transports.d.ts +3 -0
- package/dist/platform/transports.js +27 -0
- package/dist/platform/types.d.ts +7 -0
- package/dist/platform/types.js +14 -0
- package/dist/platform/wasm.browser.d.ts +2 -0
- package/dist/platform/wasm.browser.js +16 -0
- package/dist/platform/wasm.d.ts +2 -0
- package/dist/platform/wasm.js +56 -0
- package/dist/session.d.ts +316 -0
- package/dist/session.js +1269 -0
- package/dist/sync.d.ts +41 -0
- package/dist/sync.js +111 -0
- package/dist/tar.d.ts +25 -0
- package/dist/tar.js +406 -0
- package/package.json +74 -4
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Copyright 2026 Google LLC
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
// The /libp2p-http ingress in a browser: a fetch handler or a URL; a Node
|
|
15
|
+
// request listener is answered 501, there is no Node HTTP server to run it.
|
|
16
|
+
export { httpIngressHandler as ingressHandler } from "../libp2p-http.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { nodeIngressHandler as ingressHandler } from "../libp2p-http-node.ts";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Copyright 2026 Google LLC
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
// The /libp2p-http ingress on Node serves a Node request listener too.
|
|
15
|
+
export { nodeIngressHandler as ingressHandler } from "../libp2p-http-node.js";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { StateStore } from "./types.ts";
|
|
2
|
+
/** The store for a state location: a database named after it. */
|
|
3
|
+
export declare function openState(location: string): StateStore;
|
|
4
|
+
/** A browser has no file system a page may read; give the token itself. */
|
|
5
|
+
export declare function readTextFile(path: string): Promise<string>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Copyright 2026 Google LLC
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
const STORE = "state";
|
|
15
|
+
function request(req) {
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
req.onsuccess = () => resolve(req.result);
|
|
18
|
+
req.onerror = () => reject(req.error ?? new Error("IndexedDB request failed"));
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function openDatabase(name) {
|
|
22
|
+
const req = indexedDB.open(`agentmesh:${name}`, 1);
|
|
23
|
+
req.onupgradeneeded = () => {
|
|
24
|
+
req.result.createObjectStore(STORE);
|
|
25
|
+
};
|
|
26
|
+
return request(req);
|
|
27
|
+
}
|
|
28
|
+
/** The store for a state location: a database named after it. */
|
|
29
|
+
export function openState(location) {
|
|
30
|
+
let db;
|
|
31
|
+
const open = () => (db ??= openDatabase(location));
|
|
32
|
+
return {
|
|
33
|
+
async read(name) {
|
|
34
|
+
const tx = (await open()).transaction(STORE, "readonly");
|
|
35
|
+
const value = await request(tx.objectStore(STORE).get(name));
|
|
36
|
+
return value instanceof Uint8Array ? value : undefined;
|
|
37
|
+
},
|
|
38
|
+
async write(name, data) {
|
|
39
|
+
const tx = (await open()).transaction(STORE, "readwrite");
|
|
40
|
+
await request(tx.objectStore(STORE).put(new Uint8Array(data), name));
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/** A browser has no file system a page may read; give the token itself. */
|
|
45
|
+
export async function readTextFile(path) {
|
|
46
|
+
throw new Error(`cannot read ${path}: a browser has no files to read a token from; pass the value instead`);
|
|
47
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { StateStore } from "./types.ts";
|
|
2
|
+
/** The store for a state location: a directory, created on first write. */
|
|
3
|
+
export declare function openState(location: string): StateStore;
|
|
4
|
+
/** A text file, for a token an operator or a platform placed on disk. */
|
|
5
|
+
export declare function readTextFile(path: string): Promise<string>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Copyright 2026 Google LLC
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
// State on Node: a directory, one file per name, owner-only, written to a
|
|
15
|
+
// temporary name and renamed into place. Where a token file is read from.
|
|
16
|
+
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
17
|
+
import { join } from "node:path";
|
|
18
|
+
/** The store for a state location: a directory, created on first write. */
|
|
19
|
+
export function openState(location) {
|
|
20
|
+
return {
|
|
21
|
+
async read(name) {
|
|
22
|
+
try {
|
|
23
|
+
return new Uint8Array(await readFile(join(location, name)));
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
if (err.code === "ENOENT") {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
throw err;
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
async write(name, data) {
|
|
33
|
+
await mkdir(location, { recursive: true, mode: 0o700 });
|
|
34
|
+
const path = join(location, name);
|
|
35
|
+
const tmp = `${path}.tmp`;
|
|
36
|
+
await writeFile(tmp, data, { mode: 0o600 });
|
|
37
|
+
await rename(tmp, path);
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/** A text file, for a token an operator or a platform placed on disk. */
|
|
42
|
+
export async function readTextFile(path) {
|
|
43
|
+
return readFile(path, "utf8");
|
|
44
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Copyright 2026 Google LLC
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
// How a member in a browser reaches the mesh: WebSocket, the one transport a
|
|
15
|
+
// page can open to a router (agentmesh-one's single port, or a router behind a
|
|
16
|
+
// TLS-terminating proxy as wss), secured with Noise. A browser cannot run
|
|
17
|
+
// libp2p's TLS, which needs a self-signed certificate over a raw socket;
|
|
18
|
+
// routers and nodes accept Noise beside TLS, and both bind the connection to
|
|
19
|
+
// the peer ID.
|
|
20
|
+
import { noise } from "@chainsafe/libp2p-noise";
|
|
21
|
+
import { webSockets } from "@libp2p/websockets";
|
|
22
|
+
export function transports() {
|
|
23
|
+
return [webSockets()];
|
|
24
|
+
}
|
|
25
|
+
export function connectionEncrypters() {
|
|
26
|
+
return [noise()];
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Copyright 2026 Google LLC
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
// How a member on Node reaches the mesh: TCP and WebSocket, the transports
|
|
15
|
+
// the routers listen on. TLS 1.3 first, as every Go peer and the Python SDK
|
|
16
|
+
// offer it (internal/node/node.go); Noise accepted, so a member in a
|
|
17
|
+
// browser, which speaks Noise alone, is reached end to end through a relay.
|
|
18
|
+
import { noise } from "@chainsafe/libp2p-noise";
|
|
19
|
+
import { tcp } from "@libp2p/tcp";
|
|
20
|
+
import { tls } from "@libp2p/tls";
|
|
21
|
+
import { webSockets } from "@libp2p/websockets";
|
|
22
|
+
export function transports() {
|
|
23
|
+
return [tcp(), webSockets()];
|
|
24
|
+
}
|
|
25
|
+
export function connectionEncrypters() {
|
|
26
|
+
return [tls(), noise()];
|
|
27
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Where a member keeps its identity and credential between runs. */
|
|
2
|
+
export interface StateStore {
|
|
3
|
+
/** The bytes under a name, or undefined when nothing was written yet. */
|
|
4
|
+
read(name: string): Promise<Uint8Array | undefined>;
|
|
5
|
+
/** Writes the bytes under a name so that a reader sees the old or the new value, never a mix. */
|
|
6
|
+
write(name: string, data: Uint8Array): Promise<void>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Copyright 2026 Google LLC
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Copyright 2026 Google LLC
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
export async function loadBiscuitWasm() {
|
|
15
|
+
return import("@biscuit-auth/biscuit-wasm");
|
|
16
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Copyright 2026 Google LLC
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
15
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
16
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
17
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return path;
|
|
21
|
+
};
|
|
22
|
+
// biscuit-wasm is built for bundlers and imports its .wasm as a module,
|
|
23
|
+
// which Node only does behind a flag. Instantiating it by hand avoids the
|
|
24
|
+
// flag; the module's import list says what it needs.
|
|
25
|
+
import { readFile } from "node:fs/promises";
|
|
26
|
+
import { fileURLToPath } from "node:url";
|
|
27
|
+
export async function loadBiscuitWasm() {
|
|
28
|
+
const dir = new URL("./", import.meta.resolve("@biscuit-auth/biscuit-wasm"));
|
|
29
|
+
const bindings = (await import(__rewriteRelativeImportExtension(new URL("biscuit_bg.js", dir).href)));
|
|
30
|
+
const module = await WebAssembly.compile(await readFile(fileURLToPath(new URL("biscuit_bg.wasm", dir))));
|
|
31
|
+
const imports = {};
|
|
32
|
+
for (const imp of WebAssembly.Module.imports(module)) {
|
|
33
|
+
const ns = (imports[imp.module] ??= {});
|
|
34
|
+
if (imp.module === "./biscuit_bg.js") {
|
|
35
|
+
ns[imp.name] = bindings[imp.name];
|
|
36
|
+
}
|
|
37
|
+
else if (imp.name === "performance_now") {
|
|
38
|
+
ns[imp.name] = () => performance.now();
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
throw new Error(`biscuit-wasm needs an unknown import ${imp.module}:${imp.name}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const instance = await WebAssembly.instantiate(module, imports);
|
|
45
|
+
bindings.__wbg_set_wasm(instance.exports);
|
|
46
|
+
// The module's start hook logs a greeting to the console.
|
|
47
|
+
const log = console.log;
|
|
48
|
+
console.log = () => { };
|
|
49
|
+
try {
|
|
50
|
+
instance.exports.__wbindgen_start();
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
console.log = log;
|
|
54
|
+
}
|
|
55
|
+
return bindings;
|
|
56
|
+
}
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import type { MessageInitShape } from "@bufbuild/protobuf";
|
|
2
|
+
import type { Connection } from "@libp2p/interface";
|
|
3
|
+
import { type Multiaddr } from "@multiformats/multiaddr";
|
|
4
|
+
import { type VerifiedBiscuit } from "./biscuit.ts";
|
|
5
|
+
import type { RouterGoAway, RouterInfo, TaskAuthorizationRuleSchema } from "./gen/agentmesh_pb.ts";
|
|
6
|
+
import { type MeshHost, type MeshHostOptions, type RelayListener } from "./host.ts";
|
|
7
|
+
import { type MCPSession, type MCPSessionOptions } from "./mcp.ts";
|
|
8
|
+
import type { AgentMesh, ControlPlaneSync } from "./mesh.ts";
|
|
9
|
+
import { type A2AEndpoint, type A2AEndpointSpec, type HTTPRequestOptions, type HTTPResponse } from "./libp2p-http.ts";
|
|
10
|
+
import { BanSet } from "./sync.ts";
|
|
11
|
+
/** Default number of routers a member attaches to and reserves on at join. */
|
|
12
|
+
export declare const DEFAULT_ROUTERS = 2;
|
|
13
|
+
/** Default backoff delays before replacing a dropped held router. */
|
|
14
|
+
export declare const ROUTER_REDIAL_BACKOFFS_MS: readonly number[];
|
|
15
|
+
export interface JoinOptions extends MeshHostOptions {
|
|
16
|
+
/**
|
|
17
|
+
* The routers to join through, `/…/p2p/<router>` multiaddrs, instead of
|
|
18
|
+
* the ones the credential lists. A peer behind a router not named here is
|
|
19
|
+
* still reached: connect() finds it through the routers' DHT and
|
|
20
|
+
* authenticates with the router that relays for it.
|
|
21
|
+
*/
|
|
22
|
+
routerAddresses?: string[];
|
|
23
|
+
/**
|
|
24
|
+
* Number of routers to hold and reserve on at a time (agentmesh-node's --routers).
|
|
25
|
+
* Defaults to DEFAULT_ROUTERS (2).
|
|
26
|
+
*/
|
|
27
|
+
routers?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Required router labels (agentmesh-node's --router-selector): every pair must
|
|
30
|
+
* match the router's labels in ControlPlaneInfoResponse.routers.
|
|
31
|
+
*/
|
|
32
|
+
routerSelector?: Record<string, string>;
|
|
33
|
+
/**
|
|
34
|
+
* Preferred router labels (agentmesh-node's --router-prefer): routers matching
|
|
35
|
+
* more pairs are chosen ahead of others before comparing load.
|
|
36
|
+
*/
|
|
37
|
+
routerPrefer?: Record<string, string>;
|
|
38
|
+
/**
|
|
39
|
+
* Backoff delays (ms) when redialing a held router whose connection dropped
|
|
40
|
+
* before shunning it and failing over to another router from the catalog.
|
|
41
|
+
* Defaults to ROUTER_REDIAL_BACKOFFS_MS ([2000, 4000, 8000]).
|
|
42
|
+
*/
|
|
43
|
+
routerRedialBackoffsMs?: readonly number[];
|
|
44
|
+
/**
|
|
45
|
+
* Reserve a relay slot on each held router that admits us, so peers can
|
|
46
|
+
* reach this member through the routers. On by default; a member that
|
|
47
|
+
* only calls out can turn it off.
|
|
48
|
+
*/
|
|
49
|
+
reserveRelay?: boolean;
|
|
50
|
+
/** Refresh the credential this long before it expires. */
|
|
51
|
+
refreshLeadMs?: number;
|
|
52
|
+
/** Retry a failed refresh after this long. */
|
|
53
|
+
refreshRetryMs?: number;
|
|
54
|
+
/** How often the mesh policy is re-read from the control plane while accepting callers. */
|
|
55
|
+
policySyncIntervalMs?: number;
|
|
56
|
+
/**
|
|
57
|
+
* How often keys, bans and router addresses are pulled from the control
|
|
58
|
+
* plane (agentmesh-node's --control-plane-sync-interval). Gossip events bring a
|
|
59
|
+
* pull forward; 0 disables the loop.
|
|
60
|
+
*/
|
|
61
|
+
controlPlaneSyncIntervalMs?: number;
|
|
62
|
+
/** Upper bound of the random delay before a pull an event triggered. */
|
|
63
|
+
controlPlaneSyncJitterMs?: number;
|
|
64
|
+
/**
|
|
65
|
+
* How often the relay reservation is checked while reserveRelay is on: a
|
|
66
|
+
* router that restarted or trimmed the connection dropped it, and this is
|
|
67
|
+
* how long the member is unreachable at most before it reserves again.
|
|
68
|
+
*/
|
|
69
|
+
relayCheckIntervalMs?: number;
|
|
70
|
+
/**
|
|
71
|
+
* How often this member announces where it is reached under its peer
|
|
72
|
+
* key (default 5 minutes, agentmesh-node's reprovide interval).
|
|
73
|
+
*/
|
|
74
|
+
announceIntervalMs?: number;
|
|
75
|
+
/**
|
|
76
|
+
* agentmesh-node's egress.require_labels for an SDK member: every provider this
|
|
77
|
+
* session calls must attest all of these pairs, on top of a call's
|
|
78
|
+
* requiredLabels. Held on every call, MCP and HTTP alike; no call waives it.
|
|
79
|
+
*/
|
|
80
|
+
egressRequireLabels?: Record<string, string>;
|
|
81
|
+
/** Bounds the whole join. */
|
|
82
|
+
signal?: AbortSignal;
|
|
83
|
+
}
|
|
84
|
+
export interface AdmittedRouter {
|
|
85
|
+
peerId: string;
|
|
86
|
+
/**
|
|
87
|
+
* The address the connection to the router was made on, resolved: a
|
|
88
|
+
* `/ip4` or `/ip6` address ending in `/p2p/<router>`. Relay addresses
|
|
89
|
+
* are built on it. The control plane may hand a router out as
|
|
90
|
+
* `/dnsaddr/<host>/p2p/<router>`; js-libp2p resolves such an address to
|
|
91
|
+
* the TXT records themselves and drops what follows it, so a
|
|
92
|
+
* `/dnsaddr/.../p2p-circuit/p2p/<peer>` address reaches nobody.
|
|
93
|
+
*/
|
|
94
|
+
addr: Multiaddr;
|
|
95
|
+
credential: VerifiedBiscuit;
|
|
96
|
+
}
|
|
97
|
+
/** One router candidate from the control plane's /info catalog. */
|
|
98
|
+
export interface RouterCandidate {
|
|
99
|
+
peerId: string;
|
|
100
|
+
addresses: Multiaddr[];
|
|
101
|
+
labels: Record<string, string>;
|
|
102
|
+
connections: number;
|
|
103
|
+
connectionLimit: number;
|
|
104
|
+
}
|
|
105
|
+
/** A peer the DHT names as offering a service. */
|
|
106
|
+
export interface DiscoveredProvider {
|
|
107
|
+
peerId: string;
|
|
108
|
+
/** Addresses the provider advertised; may be empty when the record carried none. */
|
|
109
|
+
addrs: string[];
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* How a caller names the peer it wants to reach: a provider `discover`
|
|
113
|
+
* returned, a peer id, or a multiaddr. For a provider or a peer id the SDK
|
|
114
|
+
* dials the addresses the peer advertised and the relayed path through
|
|
115
|
+
* every router that admitted this member, so the caller never assembles a
|
|
116
|
+
* `/p2p-circuit` address. A multiaddr is dialed as given.
|
|
117
|
+
*/
|
|
118
|
+
export type Peer = DiscoveredProvider | string | Multiaddr;
|
|
119
|
+
/** A tool call's outcome, as MCP reports it. */
|
|
120
|
+
export interface ToolCallResult {
|
|
121
|
+
isError: boolean;
|
|
122
|
+
/** Text content blocks, in order; other block types are left out. */
|
|
123
|
+
text: string[];
|
|
124
|
+
/** The raw MCP result. */
|
|
125
|
+
raw: unknown;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* A member that is on the mesh: a libp2p host authenticated with at least
|
|
129
|
+
* one router, answering the auth handshake for peers that dial it, and
|
|
130
|
+
* keeping its credential fresh. Close it to leave.
|
|
131
|
+
*/
|
|
132
|
+
export declare class MeshSession {
|
|
133
|
+
#private;
|
|
134
|
+
readonly mesh: AgentMesh;
|
|
135
|
+
readonly node: MeshHost;
|
|
136
|
+
readonly routers: AdmittedRouter[];
|
|
137
|
+
/** Peers that passed the inbound auth handshake, with their credential's expiration. */
|
|
138
|
+
readonly authenticatedPeers: Map<string, Date>;
|
|
139
|
+
/** Peers the control plane has banned; connections to and from them are refused. */
|
|
140
|
+
readonly banned: BanSet;
|
|
141
|
+
/** Count of /mesh/goaway/1.0.0 frames received from held routers, keyed by reason name (DRAINING, OVERLOADED, REASON_UNSPECIFIED). */
|
|
142
|
+
readonly goAwayReceived: Map<string, number>;
|
|
143
|
+
/** Routers currently shunned (after a go-away or failed redial), mapped to the unix ms when the shun expires. */
|
|
144
|
+
readonly shunnedRouters: Map<string, number>;
|
|
145
|
+
/** This member's agent, once acceptA2A was called. */
|
|
146
|
+
endpoint: A2AEndpoint | undefined;
|
|
147
|
+
constructor(mesh: AgentMesh, node: MeshHost, routers: AdmittedRouter[], authenticatedPeers: Map<string, Date>, banned: BanSet, options: JoinOptions, relayListeners?: Map<string, RelayListener>, taskBiscuit?: Uint8Array, sharedState?: {
|
|
148
|
+
heldRouterIds: Set<string>;
|
|
149
|
+
freeRelayListeners: RelayListener[];
|
|
150
|
+
goAwayReceived: Map<string, number>;
|
|
151
|
+
shunnedRouters: Map<string, number>;
|
|
152
|
+
});
|
|
153
|
+
get peerId(): string;
|
|
154
|
+
/** The Biscuit presented on outbound service calls (task-attenuated when derived via attenuate()). */
|
|
155
|
+
get biscuit(): Uint8Array;
|
|
156
|
+
/**
|
|
157
|
+
* Returns a task-scoped MeshSession view sharing the underlying libp2p host
|
|
158
|
+
* whose outbound MCP and HTTP service calls carry a Biscuit attenuated offline
|
|
159
|
+
* in memory with rule.
|
|
160
|
+
*/
|
|
161
|
+
attenuate(rule: MessageInitShape<typeof TaskAuthorizationRuleSchema>): Promise<MeshSession>;
|
|
162
|
+
/**
|
|
163
|
+
* Returns a MeshSession view whose outbound Biscuit is sealed so downstream
|
|
164
|
+
* holders cannot append any further blocks.
|
|
165
|
+
*/
|
|
166
|
+
seal(): Promise<MeshSession>;
|
|
167
|
+
/**
|
|
168
|
+
* The URL a fetch bound to this session (fetch()) takes for a service on a
|
|
169
|
+
* peer: http://mesh/mesh/<peer-id>/<type>/<name>/<path>, the shape of
|
|
170
|
+
* agentmesh-node's egress proxy and of an agent card it rewrote.
|
|
171
|
+
*/
|
|
172
|
+
static meshURL(peerId: string, targetService: string, path?: string): string;
|
|
173
|
+
/** The mesh URL of this member's own agent, once acceptA2A was called. */
|
|
174
|
+
get agentURL(): string | undefined;
|
|
175
|
+
/** Addresses peers can dial this member on, including relayed ones. */
|
|
176
|
+
get addresses(): Multiaddr[];
|
|
177
|
+
/** The `.../p2p-circuit/p2p/<self>` addresses reserved on held routers. */
|
|
178
|
+
get relayAddresses(): Multiaddr[];
|
|
179
|
+
/**
|
|
180
|
+
* Announces where this member is reached, its relayed addresses on the
|
|
181
|
+
* routers it holds, under its peer key, so that a peer attached to other
|
|
182
|
+
* routers finds it by ID. Runs after join, when the addresses change and
|
|
183
|
+
* every announceIntervalMs; the record outlives its last announcement by
|
|
184
|
+
* the mesh's record TTL. A member with no relayed address announces
|
|
185
|
+
* nothing: there is nothing to reach it at.
|
|
186
|
+
*/
|
|
187
|
+
announce(): Promise<void>;
|
|
188
|
+
/** Whether peerId is currently one of the routers this member holds. */
|
|
189
|
+
isHeldRouter(peerId: string): boolean;
|
|
190
|
+
/** Handles a /mesh/goaway/1.0.0 message from a held router: shuns it, detaches it, and tops up from the catalog. */
|
|
191
|
+
handleGoAway(peerId: string, msg: RouterGoAway, retryAfterMs: number): Promise<void>;
|
|
192
|
+
/**
|
|
193
|
+
* Maintains held routers and relay reservations: when a held router's
|
|
194
|
+
* connection or reservation drops, redials it first (2s, 4s, 8s by default)
|
|
195
|
+
* using its current address from the catalog; if it does not recover or
|
|
196
|
+
* refuses auth, shuns it and tops up from the catalog. Runs on
|
|
197
|
+
* relayCheckIntervalMs and immediately after a /mesh/goaway/1.0.0 frame.
|
|
198
|
+
*/
|
|
199
|
+
keepRelay(): Promise<void>;
|
|
200
|
+
/**
|
|
201
|
+
* Attaches and reserves on additional routers from the catalog until this
|
|
202
|
+
* session holds wantRouters() routers or no more eligible candidates remain.
|
|
203
|
+
*/
|
|
204
|
+
topUpRouters(signal?: AbortSignal): Promise<string[]>;
|
|
205
|
+
/**
|
|
206
|
+
* Connects to a peer; see Peer for how it is named. Returns the
|
|
207
|
+
* connection, reused if one is already open. A banned peer is refused
|
|
208
|
+
* here and by the connection gater. A peer named by ID that no admitted
|
|
209
|
+
* router relays for is looked up in the routers' DHT, and failing that
|
|
210
|
+
* tried through every router the control plane lists that this member
|
|
211
|
+
* has not joined through; a relay opens a circuit only for a source it
|
|
212
|
+
* authenticated, so each such router is admitted first. Which router each
|
|
213
|
+
* side joined through does not decide whether they can talk.
|
|
214
|
+
*/
|
|
215
|
+
connect(peer: Peer, signal?: AbortSignal): Promise<Connection>;
|
|
216
|
+
/** The addresses connect() dials for a peer, in the order libp2p tries them. */
|
|
217
|
+
dialTargets(peer: Peer): {
|
|
218
|
+
peerId: string | undefined;
|
|
219
|
+
addrs: Multiaddr[];
|
|
220
|
+
};
|
|
221
|
+
/** `<router>/p2p-circuit/p2p/<peer>` through every router that admitted this member. */
|
|
222
|
+
relayedAddresses(peerId: string): Multiaddr[];
|
|
223
|
+
/** Connects to a peer and runs the mutual auth handshake, returning its verified credential. */
|
|
224
|
+
authenticate(peer: Peer, signal?: AbortSignal): Promise<VerifiedBiscuit>;
|
|
225
|
+
/**
|
|
226
|
+
* Asks the directory for peers offering a service: `"mcp://calc"`, the
|
|
227
|
+
* same string callTool and request take, or a type alone (`"mcp"`) for
|
|
228
|
+
* every service of that type, or (type, name). A router this member holds
|
|
229
|
+
* answers; bounded by the timeout.
|
|
230
|
+
*/
|
|
231
|
+
discover(service: string, name?: string, options?: {
|
|
232
|
+
timeoutMs?: number;
|
|
233
|
+
limit?: number;
|
|
234
|
+
}): Promise<DiscoveredProvider[]>;
|
|
235
|
+
/**
|
|
236
|
+
* Opens an MCP session with a provider for targetService ("mcp://<name>",
|
|
237
|
+
* or "" for the provider's own catalog tools).
|
|
238
|
+
*/
|
|
239
|
+
openMCP(peer: Peer, targetService: string, options?: MCPSessionOptions): Promise<MCPSession>;
|
|
240
|
+
/** Lists the tools a provider serves for a service. */
|
|
241
|
+
listTools(peer: Peer, targetService: string, options?: MCPSessionOptions): Promise<{
|
|
242
|
+
name: string;
|
|
243
|
+
description?: string;
|
|
244
|
+
}[]>;
|
|
245
|
+
/** Calls one tool on a provider's service. */
|
|
246
|
+
callTool(peer: Peer, targetService: string, tool: string, args?: Record<string, unknown>, options?: MCPSessionOptions): Promise<ToolCallResult>;
|
|
247
|
+
/** Refreshes now and reschedules; exposed so a caller can force it. */
|
|
248
|
+
refresh(): Promise<void>;
|
|
249
|
+
/**
|
|
250
|
+
* Pulls keys, bans and router addresses from the control plane now, and
|
|
251
|
+
* the mesh policy when accepting callers, then applies them: a newly
|
|
252
|
+
* banned peer is hung up on and dropped from the admitted set. Concurrent
|
|
253
|
+
* calls share one pull. Errors of individual parts are in the result, not
|
|
254
|
+
* thrown.
|
|
255
|
+
*/
|
|
256
|
+
sync(): Promise<ControlPlaneSync>;
|
|
257
|
+
/** Asks for a pull soon, after a random delay so a fleet told at once does not pull at once. */
|
|
258
|
+
triggerSync(): void;
|
|
259
|
+
/**
|
|
260
|
+
* The mesh policy rules this member evaluates for callers, as the control
|
|
261
|
+
* plane rendered them (PolicyConfigGetResponse.datalog_rules). Empty until
|
|
262
|
+
* the first control plane sync, acceptA2A() or syncPolicy().
|
|
263
|
+
*/
|
|
264
|
+
get policyRules(): string[];
|
|
265
|
+
/** Re-reads the mesh policy from the control plane. */
|
|
266
|
+
syncPolicy(): Promise<void>;
|
|
267
|
+
/**
|
|
268
|
+
* Calls an inference or A2A service on a provider over /libp2p-http, the
|
|
269
|
+
* way agentmesh-node's egress proxy does for /mesh/<peer>/<type>/<name>/<path>.
|
|
270
|
+
*/
|
|
271
|
+
request(peer: Peer, targetService: string, path: string, options?: HTTPRequestOptions): Promise<HTTPResponse>;
|
|
272
|
+
/**
|
|
273
|
+
* A `fetch` bound to the mesh, for clients built on fetch such as the A2A
|
|
274
|
+
* SDK's (`fetchImpl`): a request to http://mesh/mesh/<peer-id>/<type>/<name>/<path>
|
|
275
|
+
* is carried to that peer over /libp2p-http with this member's credential.
|
|
276
|
+
* Response bodies stream, so message/stream works. See MeshSession.meshURL.
|
|
277
|
+
*/
|
|
278
|
+
fetch(): typeof fetch;
|
|
279
|
+
/**
|
|
280
|
+
* Makes this member's agent reachable: other members call it as
|
|
281
|
+
* `a2a://<name>` by peer ID, through a router, and the SDK answers
|
|
282
|
+
* /libp2p-http with the spec's url (an A2A server beside this process),
|
|
283
|
+
* handler or listener (in this process; an Express app with the A2A SDK's
|
|
284
|
+
* handlers is a listener). Nothing is announced: no DHT record, no
|
|
285
|
+
* catalog entry. A tool, a model or a service others should find by name
|
|
286
|
+
* is published by a agentmesh-node. Fetches the mesh policy first and keeps it
|
|
287
|
+
* current; a policy that cannot be read fails the call, since an agent
|
|
288
|
+
* without it could only authorize what callers carry in their own tokens.
|
|
289
|
+
* Returns the service target callers use. One agent per session.
|
|
290
|
+
*/
|
|
291
|
+
acceptA2A(spec: A2AEndpointSpec): Promise<string>;
|
|
292
|
+
close(): Promise<void>;
|
|
293
|
+
}
|
|
294
|
+
export interface SelectRoutersOptions {
|
|
295
|
+
selector?: Record<string, string>;
|
|
296
|
+
prefer?: Record<string, string>;
|
|
297
|
+
attached?: ReadonlySet<string>;
|
|
298
|
+
shunned?: ReadonlyMap<string, number>;
|
|
299
|
+
nowMs?: number;
|
|
300
|
+
random?: () => number;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Builds router candidates from ControlPlaneInfoResponse.routers, falling back
|
|
304
|
+
* to router_addresses when routers is empty (an older control plane). When
|
|
305
|
+
* routerMetadata is provided alongside explicit fallbackAddresses, labels and
|
|
306
|
+
* load from routerMetadata are attached by peerId.
|
|
307
|
+
*/
|
|
308
|
+
export declare function candidatesFromRouterInfos(routers: readonly RouterInfo[], fallbackAddresses: readonly string[], routerMetadata?: readonly RouterInfo[]): RouterCandidate[];
|
|
309
|
+
/**
|
|
310
|
+
* Picks up to k routers from candidates, mirroring agentmesh-node's selectRouters:
|
|
311
|
+
* filters by selector, excludes already-attached and currently-shunned routers,
|
|
312
|
+
* and orders by matching prefer labels (descending) then load + jitter (ascending).
|
|
313
|
+
*/
|
|
314
|
+
export declare function selectRouters(candidates: readonly RouterCandidate[], k: number, options?: SelectRoutersOptions): RouterCandidate[];
|
|
315
|
+
/** Implements AgentMesh.join(); lives here to keep mesh.ts free of libp2p. */
|
|
316
|
+
export declare function joinMesh(mesh: AgentMesh, options?: JoinOptions): Promise<MeshSession>;
|