@masons/agent-network 0.6.20 → 0.6.22
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/dist/channel-setup.d.ts +0 -1
- package/dist/channel-setup.d.ts.map +1 -1
- package/dist/channel-setup.js +20 -13
- package/dist/channel.d.ts.map +1 -1
- package/dist/channel.js +54 -44
- package/dist/cli-setup.d.ts.map +1 -1
- package/dist/cli-setup.js +13 -7
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +9 -1
- package/dist/connector-client.d.ts +35 -4
- package/dist/connector-client.d.ts.map +1 -1
- package/dist/connector-client.js +126 -19
- package/dist/conversation-manager-context.d.ts +4 -0
- package/dist/conversation-manager-context.d.ts.map +1 -0
- package/dist/conversation-manager-context.js +8 -0
- package/dist/conversation-manager.d.ts +29 -4
- package/dist/conversation-manager.d.ts.map +1 -1
- package/dist/conversation-manager.js +163 -14
- package/dist/handoff-acceptance.d.ts +11 -0
- package/dist/handoff-acceptance.d.ts.map +1 -0
- package/dist/handoff-acceptance.js +62 -0
- package/dist/handoff.d.ts +0 -1
- package/dist/handoff.d.ts.map +1 -1
- package/dist/handoff.js +4 -19
- package/dist/identity-format.d.ts +6 -0
- package/dist/identity-format.d.ts.map +1 -0
- package/dist/identity-format.js +30 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/platform-client.d.ts +1 -0
- package/dist/platform-client.d.ts.map +1 -1
- package/dist/platform-client.js +24 -0
- package/dist/plugin.d.ts +2 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +49 -30
- package/dist/sent-message-buffer.d.ts +2 -3
- package/dist/sent-message-buffer.d.ts.map +1 -1
- package/dist/sent-message-buffer.js +8 -11
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +97 -20
- package/dist/turn-context.d.ts +0 -4
- package/dist/turn-context.d.ts.map +1 -1
- package/dist/turn-context.js +0 -18
- package/dist/types.d.ts +10 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/ws-heartbeat.d.ts +23 -0
- package/dist/ws-heartbeat.d.ts.map +1 -0
- package/dist/ws-heartbeat.js +63 -0
- package/openclaw.plugin.json +2 -1
- package/package.json +1 -1
- package/skills/agent-network/SKILL.md +9 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import createDebug from "debug";
|
|
2
|
+
import { writeCredentials } from "./config.js";
|
|
3
|
+
import { assertHandoffDeadlineActive, SetupFlowError, } from "./handoff-deadline.js";
|
|
4
|
+
import { classifyIdentityError, formatCanonicalNode, } from "./identity-format.js";
|
|
5
|
+
import { getIdentity, PlatformApiError, PlatformNetworkError, } from "./platform-client.js";
|
|
6
|
+
const dbg = createDebug("agent-network:handoff-acceptance");
|
|
7
|
+
const ACTIVATION_ACTION = "Messaging under this credential activates when the OpenClaw Gateway next starts or restarts.";
|
|
8
|
+
const NOTHING_CHANGED = "Nothing changed — this runtime still uses the credential it had before.";
|
|
9
|
+
export async function acceptBridgeHandoff(options) {
|
|
10
|
+
const node = await refreshCanonicalNode(options);
|
|
11
|
+
const echoed = options.handoff.agent.handle;
|
|
12
|
+
const mismatch = node.handle === echoed
|
|
13
|
+
? undefined
|
|
14
|
+
: `Note: the handoff payload claimed @${echoed}; the network says this credential represents ${node.handle ? `@${node.handle}` : node.mstpAddress}, which is the answer used here.`;
|
|
15
|
+
if (mismatch)
|
|
16
|
+
dbg(mismatch);
|
|
17
|
+
await writeCredentials({ connectorUrl: options.connectorUrl, token: options.handoff.token }, options.apiHost, options.idpBaseUrl, options.pendingTarget, () => assertHandoffDeadlineActive(options.expiresAt));
|
|
18
|
+
return formatAcceptanceReceipt(node, mismatch);
|
|
19
|
+
}
|
|
20
|
+
function formatAcceptanceReceipt(node, mismatch) {
|
|
21
|
+
const lines = [formatCanonicalNode("Accepted", node), ACTIVATION_ACTION];
|
|
22
|
+
if (mismatch)
|
|
23
|
+
lines.push(mismatch);
|
|
24
|
+
return lines.join("\n");
|
|
25
|
+
}
|
|
26
|
+
async function refreshCanonicalNode(options) {
|
|
27
|
+
let node;
|
|
28
|
+
try {
|
|
29
|
+
node = await getIdentity({ apiHost: options.apiHost }, options.handoff.token);
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
throw acceptanceFailure(err, options.apiHost);
|
|
33
|
+
}
|
|
34
|
+
if (node === null) {
|
|
35
|
+
throw new SetupFlowError(`The delivered runtime key is valid, but the network reports no active Node for it to represent, so it was not accepted. ${NOTHING_CHANGED} Choose or create an Agent Node in the console, then re-run setup.`);
|
|
36
|
+
}
|
|
37
|
+
return node;
|
|
38
|
+
}
|
|
39
|
+
function acceptanceFailure(err, apiHost) {
|
|
40
|
+
switch (classifyIdentityError(err)) {
|
|
41
|
+
case "credential-refused":
|
|
42
|
+
return new SetupFlowError(`The network rejected the runtime key delivered by the browser${httpStatusSuffix(err)}, so it was not accepted. That is a credential-class refusal — retrying will not change it. ${NOTHING_CHANGED} Re-run setup to authorize a new runtime key.`);
|
|
43
|
+
case "entity-missing":
|
|
44
|
+
return new SetupFlowError(`The delivered runtime key authenticates, but the Node it represents has no backing entity on the network — it is missing or deleted — so it was not accepted. ${NOTHING_CHANGED} Choose or create an Agent Node in the console, then re-run setup.`);
|
|
45
|
+
case "endpoint-absent":
|
|
46
|
+
return new SetupFlowError(`This MASONS Services deployment does not serve the identity endpoint (HTTP 404 for GET /v1/me/identity at ${apiHost}), so the delivered runtime key could not be verified and was not accepted. That is a property of this host — an older or self-hosted apps/api — not an expired link. ${NOTHING_CHANGED} Point setup at a Services deployment that serves the identity endpoint, or upgrade this one, then re-run setup.`);
|
|
47
|
+
case "unavailable":
|
|
48
|
+
return new SetupFlowError(`The network could not confirm which Node the delivered runtime key represents (${unavailableDetail(err)}), so it was not accepted. ${NOTHING_CHANGED} Re-run setup to try again.`);
|
|
49
|
+
default:
|
|
50
|
+
return err;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function httpStatusSuffix(err) {
|
|
54
|
+
return err instanceof PlatformApiError ? ` (HTTP ${err.status})` : "";
|
|
55
|
+
}
|
|
56
|
+
function unavailableDetail(err) {
|
|
57
|
+
if (err instanceof PlatformApiError)
|
|
58
|
+
return `HTTP ${err.status} ${err.code}`;
|
|
59
|
+
if (err instanceof PlatformNetworkError)
|
|
60
|
+
return `${err.code}: ${err.detail}`;
|
|
61
|
+
return "no answer";
|
|
62
|
+
}
|
package/dist/handoff.d.ts
CHANGED
|
@@ -20,7 +20,6 @@ export interface BridgeHandoffSession {
|
|
|
20
20
|
export interface BeginBridgeHandoffOptions {
|
|
21
21
|
apiHost: string;
|
|
22
22
|
idpBaseUrl: string;
|
|
23
|
-
channelInput?: string;
|
|
24
23
|
}
|
|
25
24
|
export declare function beginBridgeHandoff(options: BeginBridgeHandoffOptions): Promise<BridgeHandoffSession>;
|
|
26
25
|
export declare function completeBridgeHandoff(session: BridgeHandoffSession): Promise<BridgeHandoffResult>;
|
package/dist/handoff.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handoff.d.ts","sourceRoot":"","sources":["../src/handoff.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,SAAS,EAEf,MAAM,aAAa,CAAC;AAQrB,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAavD,eAAO,MAAM,oBAAoB,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"handoff.d.ts","sourceRoot":"","sources":["../src/handoff.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,SAAS,EAEf,MAAM,aAAa,CAAC;AAQrB,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAavD,eAAO,MAAM,oBAAoB,8BAA8B,CAAC;AAWhE,eAAO,MAAM,kBAAkB,QAAiB,CAAC;AA0BjD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1D;AAQD,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAOhB,UAAU,EAAE,SAAS,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAMD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,oBAAoB,CAAC,CAkD/B;AAKD,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,mBAAmB,CAAC,CA0C9B"}
|
package/dist/handoff.js
CHANGED
|
@@ -3,9 +3,9 @@ import { assertHandoffDeadlineActive, SetupFlowError, } from "./handoff-deadline
|
|
|
3
3
|
import { apiFetch, PlatformNetworkError } from "./platform-client.js";
|
|
4
4
|
export { SetupFlowError } from "./handoff-deadline.js";
|
|
5
5
|
export const DEFAULT_IDP_BASE_URL = "https://preview.masons.ai";
|
|
6
|
-
const HANDLE_REGEX = /^[a-z][a-z0-9_-]{2,14}$/;
|
|
7
6
|
export const HANDOFF_TIMEOUT_MS = 10 * 60 * 1000;
|
|
8
7
|
const HANDOFF_POLL_INTERVAL_MS = 2000;
|
|
8
|
+
const RUNTIME_KEY_PATTERN = /^masons_rt_v1_[A-Za-z0-9_-]+$/;
|
|
9
9
|
export async function beginBridgeHandoff(options) {
|
|
10
10
|
const { publicKey, privateKey } = generateKeyPairSync("rsa", {
|
|
11
11
|
modulusLength: 2048,
|
|
@@ -39,11 +39,7 @@ export async function beginBridgeHandoff(options) {
|
|
|
39
39
|
const message = err instanceof Error ? err.message : "unknown error";
|
|
40
40
|
throw new SetupFlowError(`Could not reach the setup service at ${apiBase} (${message}). Retry in a moment.`);
|
|
41
41
|
}
|
|
42
|
-
const
|
|
43
|
-
const handoffPath = handle
|
|
44
|
-
? `/console/agents/${encodeURIComponent(handle)}/runtime-keys/handoff`
|
|
45
|
-
: "/console/handoff";
|
|
46
|
-
const handoffUrl = `${options.idpBaseUrl}${handoffPath}?session=${encodeURIComponent(sessionId)}`;
|
|
42
|
+
const handoffUrl = `${options.idpBaseUrl}/console/handoff?session=${encodeURIComponent(sessionId)}`;
|
|
47
43
|
return {
|
|
48
44
|
sessionId,
|
|
49
45
|
handoffUrl,
|
|
@@ -64,10 +60,10 @@ export async function completeBridgeHandoff(session) {
|
|
|
64
60
|
}
|
|
65
61
|
assertHandoffDeadlineActive(session.expiresAt);
|
|
66
62
|
if (typeof payload.token !== "string" ||
|
|
67
|
-
!payload.token
|
|
63
|
+
!RUNTIME_KEY_PATTERN.test(payload.token) ||
|
|
68
64
|
typeof payload.agent?.handle !== "string" ||
|
|
69
65
|
typeof payload.agent?.agentId !== "string") {
|
|
70
|
-
throw new SetupFlowError("Handoff payload
|
|
66
|
+
throw new SetupFlowError("Handoff payload did not match the expected shape. Re-run setup; if it keeps happening, this is a server-side bug worth reporting.");
|
|
71
67
|
}
|
|
72
68
|
return {
|
|
73
69
|
token: payload.token,
|
|
@@ -154,17 +150,6 @@ function normalizeHttpBase(apiHost) {
|
|
|
154
150
|
return trimmed;
|
|
155
151
|
return `https://${trimmed}`;
|
|
156
152
|
}
|
|
157
|
-
function parseHandleFromInput(input) {
|
|
158
|
-
if (typeof input !== "string")
|
|
159
|
-
return undefined;
|
|
160
|
-
const trimmed = input.trim().toLowerCase();
|
|
161
|
-
if (!trimmed.startsWith("@"))
|
|
162
|
-
return undefined;
|
|
163
|
-
const handle = trimmed.slice(1);
|
|
164
|
-
if (!HANDLE_REGEX.test(handle))
|
|
165
|
-
return undefined;
|
|
166
|
-
return handle;
|
|
167
|
-
}
|
|
168
153
|
function sleep(ms) {
|
|
169
154
|
return new Promise((resolve) => {
|
|
170
155
|
setTimeout(resolve, ms);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type ConnectionNodeRef } from "./platform-client.js";
|
|
2
|
+
export declare function formatKindLabel(kind: string | undefined): string;
|
|
3
|
+
export declare function formatCanonicalNode(label: string, node: ConnectionNodeRef): string;
|
|
4
|
+
export type IdentityErrorClass = "credential-refused" | "entity-missing" | "endpoint-absent" | "unavailable";
|
|
5
|
+
export declare function classifyIdentityError(err: unknown): IdentityErrorClass | null;
|
|
6
|
+
//# sourceMappingURL=identity-format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity-format.d.ts","sourceRoot":"","sources":["../src/identity-format.ts"],"names":[],"mappings":"AAWA,OAAO,EACL,KAAK,iBAAiB,EAGvB,MAAM,sBAAsB,CAAC;AAe9B,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAKhE;AAYD,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,iBAAiB,GACtB,MAAM,CAKR;AAgBD,MAAM,MAAM,kBAAkB,GAC1B,oBAAoB,GACpB,gBAAgB,GAChB,iBAAiB,GACjB,aAAa,CAAC;AAOlB,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,kBAAkB,GAAG,IAAI,CAU7E"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { PlatformApiError, PlatformNetworkError, } from "./platform-client.js";
|
|
2
|
+
export function formatKindLabel(kind) {
|
|
3
|
+
if (!kind)
|
|
4
|
+
return "";
|
|
5
|
+
if (kind === "user")
|
|
6
|
+
return "[Human Node] ";
|
|
7
|
+
if (kind === "agent")
|
|
8
|
+
return "[Agent Node] ";
|
|
9
|
+
return `[Node:${kind}] `;
|
|
10
|
+
}
|
|
11
|
+
export function formatCanonicalNode(label, node) {
|
|
12
|
+
const handlePart = node.handle ? `@${node.handle} — ` : "";
|
|
13
|
+
const canonical = `${label}: ${formatKindLabel(node.kind)}${handlePart}${node.mstpAddress}`;
|
|
14
|
+
if (!node.displayName)
|
|
15
|
+
return canonical;
|
|
16
|
+
return `${canonical}\nDisplay name (presentation supplied by the identity endpoint): ${node.displayName}`;
|
|
17
|
+
}
|
|
18
|
+
export function classifyIdentityError(err) {
|
|
19
|
+
if (err instanceof PlatformApiError) {
|
|
20
|
+
if (err.status === 401 || err.status === 403)
|
|
21
|
+
return "credential-refused";
|
|
22
|
+
if (err.status === 404) {
|
|
23
|
+
return err.code === "not_found" ? "entity-missing" : "endpoint-absent";
|
|
24
|
+
}
|
|
25
|
+
return "unavailable";
|
|
26
|
+
}
|
|
27
|
+
if (err instanceof PlatformNetworkError)
|
|
28
|
+
return "unavailable";
|
|
29
|
+
return null;
|
|
30
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { AUTHORIZED_TOKEN_TTL_MS, SETUP_CODE_CHARSET, SETUP_CODE_LENGTH, SETUP_CODE_TTL_MS, } from "./constants.js";
|
|
2
2
|
export type { AgentNetworkAccount } from "./config-schema.js";
|
|
3
|
-
export type { AddressedMessageEvent, DeliveryPendingEvent, DeliverySkipEvent, DeliveryStatusEvent, RegisterAckEvent, SendAckEvent, StructuredErrorEvent, } from "./types.js";
|
|
3
|
+
export type { AddressedMessageEvent, DeliveryPendingEvent, DeliverySkipEvent, DeliveryStatusEvent, ObservedSendAckEvent, RegisterAckEvent, SendAckEvent, StructuredErrorEvent, } from "./types.js";
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAIxB,YAAY,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,YAAY,EACV,qBAAqB,EACrB,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,YAAY,EACZ,oBAAoB,GACrB,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAIxB,YAAY,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,YAAY,EACV,qBAAqB,EACrB,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,YAAY,EACZ,oBAAoB,GACrB,MAAM,YAAY,CAAC"}
|
|
@@ -87,4 +87,5 @@ export declare function acceptRequest(cfg: PlatformClientConfig, runtimeKey: str
|
|
|
87
87
|
export declare function declineRequest(cfg: PlatformClientConfig, runtimeKey: string, requestId: string): Promise<DeclineRequestResponse>;
|
|
88
88
|
export declare function updateProfile(cfg: PlatformClientConfig, runtimeKey: string, params: UpdateProfileParams): Promise<UpdateProfileResponse>;
|
|
89
89
|
export declare function listConnections(cfg: PlatformClientConfig, runtimeKey: string): Promise<ListConnectionsResponse>;
|
|
90
|
+
export declare function getIdentity(cfg: PlatformClientConfig, runtimeKey: string): Promise<ConnectionNodeRef | null>;
|
|
90
91
|
//# sourceMappingURL=platform-client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform-client.d.ts","sourceRoot":"","sources":["../src/platform-client.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,gBAAgB,0BAA0B,CAAC;AASxD,eAAO,MAAM,qBAAqB,iDACc,CAAC;AAEjD,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD,qBAAa,gBAAiB,SAAQ,KAAK;aAEvB,MAAM,EAAE,MAAM;aACd,IAAI,EAAE,MAAM;gBADZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EAC5B,OAAO,EAAE,MAAM;CAKlB;AAiBD,qBAAa,oBAAqB,SAAQ,KAAK;aAE3B,IAAI,EAAE,SAAS,GAAG,SAAS;aAE3B,MAAM,EAAE,MAAM;gBAFd,IAAI,EAAE,SAAS,GAAG,SAAS,EAE3B,MAAM,EAAE,MAAM;CAKjC;AAMD,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;
|
|
1
|
+
{"version":3,"file":"platform-client.d.ts","sourceRoot":"","sources":["../src/platform-client.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,gBAAgB,0BAA0B,CAAC;AASxD,eAAO,MAAM,qBAAqB,iDACc,CAAC;AAEjD,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD,qBAAa,gBAAiB,SAAQ,KAAK;aAEvB,MAAM,EAAE,MAAM;aACd,IAAI,EAAE,MAAM;gBADZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EAC5B,OAAO,EAAE,MAAM;CAKlB;AAiBD,qBAAa,oBAAqB,SAAQ,KAAK;aAE3B,IAAI,EAAE,SAAS,GAAG,SAAS;aAE3B,MAAM,EAAE,MAAM;gBAFd,IAAI,EAAE,SAAS,GAAG,SAAS,EAE3B,MAAM,EAAE,MAAM;CAKjC;AAMD,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAYD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,UAAU,GAAG,UAAU,CAAC;IAEnC,QAAQ,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAEpC,MAAM,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE;QACX,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;KACzB,CAAC;IACF,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,gBAAgB,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,UAAU,CAAC;IACnB,YAAY,EAAE,iBAAiB,GAAG,IAAI,CAAC;CACxC;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,UAAU,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,SAAS,CAAC;IAClB,OAAO,CAAC,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,KAAK,CAAC;QACjB,YAAY,EAAE,iBAAiB,CAAC;QAChC,MAAM,EAAE,QAAQ,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;QACnD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;KAC1B,CAAC,CAAC;CACJ;AAyGD,wBAAsB,QAAQ,CAC5B,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,QAAQ,CAAC,CAanB;AAYD,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,oBAAoB,EACzB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,CAAC,YAAY,GAAG,SAAS,CAAC,EAAE,CAAA;CAAE,GACvE,OAAO,CAAC,yBAAyB,CAAC,CAWpC;AAQD,wBAAsB,YAAY,CAChC,GAAG,EAAE,oBAAoB,EACzB,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE;IACP,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GACA,OAAO,CAAC,oBAAoB,CAAC,CAc/B;AAOD,wBAAsB,aAAa,CACjC,GAAG,EAAE,oBAAoB,EACzB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,qBAAqB,CAAC,CAUhC;AAOD,wBAAsB,cAAc,CAClC,GAAG,EAAE,oBAAoB,EACzB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,sBAAsB,CAAC,CAUjC;AAQD,wBAAsB,aAAa,CACjC,GAAG,EAAE,oBAAoB,EACzB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,qBAAqB,CAAC,CAWhC;AAQD,wBAAsB,eAAe,CACnC,GAAG,EAAE,oBAAoB,EACzB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,uBAAuB,CAAC,CAMlC;AA4BD,wBAAsB,WAAW,CAC/B,GAAG,EAAE,oBAAoB,EACzB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAyBnC"}
|
package/dist/platform-client.js
CHANGED
|
@@ -144,3 +144,27 @@ export async function listConnections(cfg, runtimeKey) {
|
|
|
144
144
|
return handleError(res);
|
|
145
145
|
return (await res.json());
|
|
146
146
|
}
|
|
147
|
+
export async function getIdentity(cfg, runtimeKey) {
|
|
148
|
+
const res = await apiFetch(`${baseUrl(cfg)}/me/identity`, {
|
|
149
|
+
headers: { Authorization: `Bearer ${runtimeKey}` },
|
|
150
|
+
});
|
|
151
|
+
if (!res.ok)
|
|
152
|
+
return handleError(res);
|
|
153
|
+
const body = (await res.json().catch(() => null));
|
|
154
|
+
if (!body || body.node === undefined) {
|
|
155
|
+
throw new PlatformApiError(res.status, "malformed_response", "identity response carried no `node` field");
|
|
156
|
+
}
|
|
157
|
+
if (body.node === null)
|
|
158
|
+
return null;
|
|
159
|
+
if (!isNodeRef(body.node)) {
|
|
160
|
+
throw new PlatformApiError(res.status, "malformed_response", "identity response `node` carried no mstpAddress");
|
|
161
|
+
}
|
|
162
|
+
return body.node;
|
|
163
|
+
}
|
|
164
|
+
function isNodeRef(value) {
|
|
165
|
+
return (typeof value === "object" &&
|
|
166
|
+
value !== null &&
|
|
167
|
+
"mstpAddress" in value &&
|
|
168
|
+
typeof value.mstpAddress === "string" &&
|
|
169
|
+
value.mstpAddress.length > 0);
|
|
170
|
+
}
|
package/dist/plugin.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { ConversationManager } from "./conversation-manager.js";
|
|
1
2
|
import { evaluateServicesRetainedToolPolicy } from "./services-retained-tool-policy.js";
|
|
2
|
-
export declare function buildInteractionContext(
|
|
3
|
+
export declare function buildInteractionContext(messageProvider: string | undefined, turnSenderAddress: string | null, conversationManager?: ConversationManager | null): string | undefined;
|
|
3
4
|
interface OpenClawPluginApi {
|
|
4
5
|
runtime: unknown;
|
|
5
6
|
registerChannel(opts: {
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAUrE,OAAO,EACL,kCAAkC,EAEnC,MAAM,oCAAoC,CAAC;AA8D5C,wBAAgB,uBAAuB,CACrC,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,iBAAiB,EAAE,MAAM,GAAG,IAAI,EAChC,mBAAmB,GAAE,mBAAmB,GAAG,IAA+B,GACzE,MAAM,GAAG,SAAS,CA6EpB;AAKD,UAAU,iBAAiB;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IACjD,YAAY,CACV,IAAI,EAAE,OAAO,EACb,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAC3C,IAAI,CAAC;IACR,yBAAyB,CAAC,MAAM,EAAE;QAChC,EAAE,EAAE,MAAM,CAAC;QACX,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,OAAO,kCAAkC,CAAC;KACrD,GAAG,IAAI,CAAC;IACT,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,GAAG,IAAI,CAAC;CACnE;AAqCD,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAaI,iBAAiB;CA8ZhC,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
package/dist/plugin.js
CHANGED
|
@@ -2,14 +2,14 @@ import pluginManifest from "../openclaw.plugin.json" with { type: "json" };
|
|
|
2
2
|
import { agentNetworkChannel, consumeIdentityLinkingNudge } from "./channel.js";
|
|
3
3
|
import { login } from "./cli-setup.js";
|
|
4
4
|
import { detectPendingState, getConversationManager, getDmScope, getStateCacheGeneration, initPluginRuntime, } from "./config.js";
|
|
5
|
+
import { getInvocationConversationManager } from "./conversation-manager-context.js";
|
|
5
6
|
import { getAgentIdentity } from "./environment-context.js";
|
|
6
7
|
import { ownerNotesQueue } from "./owner-notes.js";
|
|
7
8
|
import { consumeCurrentTurnIsOwner, consumeCurrentTurnOwnerSignal, } from "./owner-session-state.js";
|
|
8
|
-
import { sentMessageBuffer } from "./sent-message-buffer.js";
|
|
9
9
|
import { isServicesRetainedReplyContext } from "./services-retained-reply-context.js";
|
|
10
10
|
import { evaluateServicesRetainedToolPolicy, SERVICES_RETAINED_TOOL_POLICY_ID, } from "./services-retained-tool-policy.js";
|
|
11
11
|
import { registerTools } from "./tools.js";
|
|
12
|
-
import {
|
|
12
|
+
import { setCurrentTurnChannelId, setCurrentTurnIsOwnerForTools, setCurrentTurnOwnerSignalForTools, } from "./turn-context.js";
|
|
13
13
|
import { getUpdateInfo } from "./update-check.js";
|
|
14
14
|
import { PLUGIN_VERSION } from "./version.js";
|
|
15
15
|
function formatTimeAgo(timestamp) {
|
|
@@ -40,8 +40,8 @@ function drainAndFormatNotes(reportInstruction) {
|
|
|
40
40
|
reportInstruction);
|
|
41
41
|
}
|
|
42
42
|
const MAX_INTERACTIONS = 5;
|
|
43
|
-
export function buildInteractionContext(
|
|
44
|
-
const cm =
|
|
43
|
+
export function buildInteractionContext(messageProvider, turnSenderAddress, conversationManager = getConversationManager()) {
|
|
44
|
+
const cm = conversationManager;
|
|
45
45
|
if (!cm)
|
|
46
46
|
return undefined;
|
|
47
47
|
const conversations = cm.listConversations();
|
|
@@ -60,22 +60,18 @@ export function buildInteractionContext(channelId, turnSender, turnSenderAddress
|
|
|
60
60
|
const when = formatTimeAgo(c.lastMessageAt);
|
|
61
61
|
return `• ${who} — ${initiated} — last activity ${when}`;
|
|
62
62
|
});
|
|
63
|
-
const isNetworkTurn =
|
|
64
|
-
if (isNetworkTurn &&
|
|
65
|
-
const senderConvo = turnSenderAddress
|
|
66
|
-
? conversations.find((c) => c.address === turnSenderAddress)
|
|
67
|
-
: undefined;
|
|
63
|
+
const isNetworkTurn = messageProvider === "agent-network";
|
|
64
|
+
if (isNetworkTurn && turnSenderAddress) {
|
|
65
|
+
const senderConvo = conversations.find((c) => c.address === turnSenderAddress);
|
|
68
66
|
const initiated = senderConvo?.initiatedBy === "local"
|
|
69
67
|
? "You initiated this interaction."
|
|
70
68
|
: "They initiated this interaction.";
|
|
71
|
-
const from =
|
|
72
|
-
? `${
|
|
73
|
-
:
|
|
69
|
+
const from = senderConvo && senderConvo.contact !== turnSenderAddress
|
|
70
|
+
? `${senderConvo.contact} (${turnSenderAddress})`
|
|
71
|
+
: turnSenderAddress;
|
|
74
72
|
return (`${header}\n${lines.join("\n")}\n` +
|
|
75
73
|
`[This turn] From ${from}. ${initiated}\n` +
|
|
76
|
-
|
|
77
|
-
? "Your text reply uses the Services-retained reply authority for this message. "
|
|
78
|
-
: "Your text reply goes to this sender. ") +
|
|
74
|
+
"Your text reply goes to this sender. " +
|
|
79
75
|
"To report to your owner: masons_note_for_owner.");
|
|
80
76
|
}
|
|
81
77
|
if (isNetworkTurn) {
|
|
@@ -88,6 +84,24 @@ export function buildInteractionContext(channelId, turnSender, turnSenderAddress
|
|
|
88
84
|
: "[Active interactions on the network]";
|
|
89
85
|
return `${ownerHeader}\n${lines.join("\n")}`;
|
|
90
86
|
}
|
|
87
|
+
function resolveHookProvider(ctx) {
|
|
88
|
+
return ctx?.messageProvider ?? ctx?.channel;
|
|
89
|
+
}
|
|
90
|
+
function resolveHookSender(ctx, servicesRetained) {
|
|
91
|
+
if (servicesRetained || resolveHookProvider(ctx) !== "agent-network") {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
const senderId = ctx?.senderId;
|
|
95
|
+
return typeof senderId === "string" && senderId.length > 0 ? senderId : null;
|
|
96
|
+
}
|
|
97
|
+
function renderPeer(address, conversationManager) {
|
|
98
|
+
const conversation = conversationManager
|
|
99
|
+
.listConversations()
|
|
100
|
+
.find((entry) => entry.address === address);
|
|
101
|
+
return conversation && conversation.contact !== address
|
|
102
|
+
? `${conversation.contact} (${address})`
|
|
103
|
+
: address;
|
|
104
|
+
}
|
|
91
105
|
const plugin = {
|
|
92
106
|
id: "agent-network",
|
|
93
107
|
version: PLUGIN_VERSION,
|
|
@@ -130,7 +144,8 @@ const plugin = {
|
|
|
130
144
|
"masons_note_for_owner(content, from?) — save a note for your owner's next turn. " +
|
|
131
145
|
"Other network tools: masons_list_requests, masons_send_connection_request, " +
|
|
132
146
|
"masons_accept_request, masons_decline_request, masons_list_connections, " +
|
|
133
|
-
"masons_end_conversation (rare one-shot close signal only)
|
|
147
|
+
"masons_end_conversation (rare one-shot close signal only), " +
|
|
148
|
+
"masons_status (your canonical identity and participation status). " +
|
|
134
149
|
"Always try these tools first for network operations. " +
|
|
135
150
|
"If a tool call fails, report the error to your user — do not silently work around it. " +
|
|
136
151
|
"You interact with multiple entities simultaneously — your owner and agents on the network. " +
|
|
@@ -147,13 +162,15 @@ const plugin = {
|
|
|
147
162
|
"";
|
|
148
163
|
api.on("before_prompt_build", async (_event, ctx) => {
|
|
149
164
|
const hookCtx = ctx;
|
|
150
|
-
const
|
|
165
|
+
const messageProvider = resolveHookProvider(hookCtx);
|
|
166
|
+
const invocationConversationManager = getInvocationConversationManager();
|
|
151
167
|
const turnIsOwner = consumeCurrentTurnIsOwner();
|
|
152
168
|
const turnOwnerSignal = consumeCurrentTurnOwnerSignal();
|
|
153
|
-
const turnSender = consumeCurrentTurnSender();
|
|
154
|
-
const turnSenderAddress = consumeCurrentTurnSenderAddress();
|
|
155
169
|
const servicesRetainedReply = isServicesRetainedReplyContext();
|
|
156
|
-
|
|
170
|
+
const turnSenderAddress = invocationConversationManager
|
|
171
|
+
? resolveHookSender(hookCtx, servicesRetainedReply)
|
|
172
|
+
: null;
|
|
173
|
+
setCurrentTurnChannelId(messageProvider ?? null);
|
|
157
174
|
setCurrentTurnIsOwnerForTools(turnIsOwner);
|
|
158
175
|
setCurrentTurnOwnerSignalForTools(turnOwnerSignal);
|
|
159
176
|
const currentGeneration = getStateCacheGeneration();
|
|
@@ -203,7 +220,7 @@ const plugin = {
|
|
|
203
220
|
state.hasCredentials &&
|
|
204
221
|
!state.needsProfile &&
|
|
205
222
|
!state.pendingTarget) {
|
|
206
|
-
if (
|
|
223
|
+
if (messageProvider === "agent-network") {
|
|
207
224
|
if (turnIsOwner) {
|
|
208
225
|
dynamicContext =
|
|
209
226
|
"[Agent Network — Owner via Passport] Your owner (Principal) is talking to you " +
|
|
@@ -226,12 +243,12 @@ const plugin = {
|
|
|
226
243
|
"on the agent network. Your text reply will be sent to that sender — " +
|
|
227
244
|
"your owner (Principal) will NOT see it. To report something to your owner, " +
|
|
228
245
|
"call masons_note_for_owner.";
|
|
229
|
-
const interactionCtx = buildInteractionContext(
|
|
246
|
+
const interactionCtx = buildInteractionContext(messageProvider, turnSenderAddress, invocationConversationManager);
|
|
230
247
|
if (interactionCtx) {
|
|
231
248
|
dynamicContext += `\n\n${interactionCtx}`;
|
|
232
249
|
}
|
|
233
|
-
if (
|
|
234
|
-
const sentMsgs =
|
|
250
|
+
if (turnSenderAddress && invocationConversationManager) {
|
|
251
|
+
const sentMsgs = invocationConversationManager?.getRecentOutboundContext(turnSenderAddress) ?? [];
|
|
235
252
|
if (sentMsgs.length > 0) {
|
|
236
253
|
const lines = sentMsgs.map((m) => {
|
|
237
254
|
const preview = m.content.length > 500
|
|
@@ -240,7 +257,7 @@ const plugin = {
|
|
|
240
257
|
return `• (${formatTimeAgo(m.timestamp)}): "${preview}"`;
|
|
241
258
|
});
|
|
242
259
|
dynamicContext +=
|
|
243
|
-
`\n\n[Your recent messages to ${
|
|
260
|
+
`\n\n[Your recent messages to ${renderPeer(turnSenderAddress, invocationConversationManager)}]\n` +
|
|
244
261
|
lines.join("\n");
|
|
245
262
|
}
|
|
246
263
|
}
|
|
@@ -261,7 +278,7 @@ const plugin = {
|
|
|
261
278
|
? `${dynamicContext}\n\n${nudge}`
|
|
262
279
|
: nudge;
|
|
263
280
|
}
|
|
264
|
-
const interactionCtx = buildInteractionContext(
|
|
281
|
+
const interactionCtx = buildInteractionContext(messageProvider, null);
|
|
265
282
|
if (interactionCtx) {
|
|
266
283
|
dynamicContext = dynamicContext
|
|
267
284
|
? `${dynamicContext}\n\n${interactionCtx}`
|
|
@@ -287,10 +304,12 @@ const plugin = {
|
|
|
287
304
|
if (state.hasCredentials) {
|
|
288
305
|
const envAgent = getAgentIdentity();
|
|
289
306
|
if (envAgent) {
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
identityLine
|
|
307
|
+
const registered = envAgent.name
|
|
308
|
+
? `@${envAgent.handle}(${envAgent.name})`
|
|
309
|
+
: `@${envAgent.handle}`;
|
|
310
|
+
const identityLine = `[Identity] The Gateway registered this connection as ${registered}. ` +
|
|
311
|
+
"This is connection-level context, not your canonical network identity — " +
|
|
312
|
+
"for the canonical answer, call masons_status.";
|
|
294
313
|
dynamicContext = dynamicContext
|
|
295
314
|
? `${identityLine}\n\n${dynamicContext}`
|
|
296
315
|
: identityLine;
|
|
@@ -7,9 +7,8 @@ export declare class SentMessageBuffer {
|
|
|
7
7
|
static readonly MAX_PER_CONTACT = 5;
|
|
8
8
|
static readonly TTL_MS: number;
|
|
9
9
|
static readonly MAX_CONTENT_LENGTH = 1000;
|
|
10
|
-
record(
|
|
11
|
-
getRecent(
|
|
10
|
+
record(peerAddress: string, content: string): void;
|
|
11
|
+
getRecent(peerAddress: string): SentMessage[];
|
|
12
12
|
clear(): void;
|
|
13
13
|
}
|
|
14
|
-
export declare const sentMessageBuffer: SentMessageBuffer;
|
|
15
14
|
//# sourceMappingURL=sent-message-buffer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sent-message-buffer.d.ts","sourceRoot":"","sources":["../src/sent-message-buffer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sent-message-buffer.d.ts","sourceRoot":"","sources":["../src/sent-message-buffer.ts"],"names":[],"mappings":"AAsBA,MAAM,WAAW,WAAW;IAE1B,OAAO,EAAE,MAAM,CAAC;IAEhB,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,OAAO,CAAoC;IAGnD,MAAM,CAAC,QAAQ,CAAC,eAAe,KAAK;IAEpC,MAAM,CAAC,QAAQ,CAAC,MAAM,SAAsB;IAE5C,MAAM,CAAC,QAAQ,CAAC,kBAAkB,QAAQ;IAM1C,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAgClD,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,EAAE;IAsB7C,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -3,13 +3,12 @@ export class SentMessageBuffer {
|
|
|
3
3
|
static MAX_PER_CONTACT = 5;
|
|
4
4
|
static TTL_MS = 2 * 60 * 60 * 1000;
|
|
5
5
|
static MAX_CONTENT_LENGTH = 1000;
|
|
6
|
-
record(
|
|
6
|
+
record(peerAddress, content) {
|
|
7
7
|
const now = Date.now();
|
|
8
|
-
|
|
9
|
-
let list = this.entries.get(key);
|
|
8
|
+
let list = this.entries.get(peerAddress);
|
|
10
9
|
if (!list) {
|
|
11
10
|
list = [];
|
|
12
|
-
this.entries.set(
|
|
11
|
+
this.entries.set(peerAddress, list);
|
|
13
12
|
}
|
|
14
13
|
const cutoff = now - SentMessageBuffer.TTL_MS;
|
|
15
14
|
const fresh = list.filter((m) => m.timestamp > cutoff);
|
|
@@ -20,21 +19,20 @@ export class SentMessageBuffer {
|
|
|
20
19
|
? `${content.slice(0, SentMessageBuffer.MAX_CONTENT_LENGTH)}...`
|
|
21
20
|
: content;
|
|
22
21
|
fresh.push({ content: stored, timestamp: now });
|
|
23
|
-
this.entries.set(
|
|
22
|
+
this.entries.set(peerAddress, fresh);
|
|
24
23
|
}
|
|
25
|
-
getRecent(
|
|
26
|
-
const
|
|
27
|
-
const list = this.entries.get(key);
|
|
24
|
+
getRecent(peerAddress) {
|
|
25
|
+
const list = this.entries.get(peerAddress);
|
|
28
26
|
if (!list)
|
|
29
27
|
return [];
|
|
30
28
|
const cutoff = Date.now() - SentMessageBuffer.TTL_MS;
|
|
31
29
|
const fresh = list.filter((m) => m.timestamp > cutoff);
|
|
32
30
|
if (fresh.length !== list.length) {
|
|
33
31
|
if (fresh.length === 0) {
|
|
34
|
-
this.entries.delete(
|
|
32
|
+
this.entries.delete(peerAddress);
|
|
35
33
|
}
|
|
36
34
|
else {
|
|
37
|
-
this.entries.set(
|
|
35
|
+
this.entries.set(peerAddress, fresh);
|
|
38
36
|
}
|
|
39
37
|
}
|
|
40
38
|
return fresh;
|
|
@@ -43,4 +41,3 @@ export class SentMessageBuffer {
|
|
|
43
41
|
this.entries.clear();
|
|
44
42
|
}
|
|
45
43
|
}
|
|
46
|
-
export const sentMessageBuffer = new SentMessageBuffer();
|
package/dist/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AA+EA,UAAU,WAAW;IACnB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChD;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,CACP,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,OAAO,CAAC,WAAW,CAAC,CAAC;CAC3B;AAED,UAAU,WAAW;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,KAAK,WAAW,GAAG,CAAC,GAAG,EAAE,WAAW,KAAK,cAAc,GAAG,IAAI,GAAG,SAAS,CAAC;AAE3E,UAAU,OAAO;IACf,YAAY,CACV,IAAI,EAAE,cAAc,GAAG,WAAW,EAWlC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,GAC7D,IAAI,CAAC;CACT;AAoDD,wBAAgB,qBAAqB,IAAI,IAAI,CAG5C;AA8WD,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAm5BhD"}
|