@masons/agent-network 0.4.16 → 0.4.17
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.d.ts.map +1 -1
- package/dist/channel.js +154 -195
- package/dist/connector-client.d.ts +46 -24
- package/dist/connector-client.d.ts.map +1 -1
- package/dist/connector-client.js +123 -76
- package/dist/conversation-manager.d.ts +40 -33
- package/dist/conversation-manager.d.ts.map +1 -1
- package/dist/conversation-manager.js +103 -80
- package/dist/handle-utils.d.ts +16 -0
- package/dist/handle-utils.d.ts.map +1 -0
- package/dist/handle-utils.js +25 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/owner-session-state.d.ts +11 -18
- package/dist/owner-session-state.d.ts.map +1 -1
- package/dist/owner-session-state.js +17 -26
- package/dist/tools.d.ts +1 -2
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +2 -33
- package/dist/types.d.ts +47 -58
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +18 -33
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -2,40 +2,57 @@
|
|
|
2
2
|
* Conversation Manager — maps contacts to conversations.
|
|
3
3
|
*
|
|
4
4
|
* Owns the identity-based API that the Tool Interface and Inbound Dispatcher
|
|
5
|
-
* call.
|
|
5
|
+
* call. Sends messages directly to routable addresses via ConnectorClient.send().
|
|
6
6
|
*
|
|
7
|
-
* Contact resolution: handle
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* Contact resolution: handle → `mstps://${connectorHost}/${handle}`
|
|
8
|
+
* Address schemes: MSTP (`mstps://`), handle (bare), passport (`passport:@`)
|
|
9
|
+
* Internal key: routable address.
|
|
10
|
+
* One conversation per contact, in-memory only (D3).
|
|
11
11
|
*
|
|
12
|
-
* @see docs/
|
|
12
|
+
* @see docs/connector/gateway-v2-consumer-adaptation-plan.md PR 2
|
|
13
13
|
*/
|
|
14
14
|
import createDebug from "debug";
|
|
15
|
-
import {
|
|
15
|
+
import { ConnectorError } from "./connector-client.js";
|
|
16
|
+
import { extractHandleFromAddress } from "./handle-utils.js";
|
|
16
17
|
const dbg = createDebug("agent-network:conversation-manager");
|
|
17
18
|
// ---------------------------------------------------------------------------
|
|
19
|
+
// Error code → tool result mapping
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
const ERROR_MESSAGES = {
|
|
22
|
+
ADDRESS_NOT_FOUND: "Cannot find agent '{to}'. Check the handle.",
|
|
23
|
+
ACCESS_DENIED: "No connection to '{to}'. Send a connection request first.",
|
|
24
|
+
RECIPIENT_UNREACHABLE: "Agent '{to}' is currently unreachable. Try again later.",
|
|
25
|
+
MAILBOX_FULL: "Agent '{to}' mailbox is full. Try again later.",
|
|
26
|
+
INTERNAL_ERROR: "Network error. Try again.",
|
|
27
|
+
};
|
|
28
|
+
function formatErrorMessage(code, to) {
|
|
29
|
+
const template = ERROR_MESSAGES[code] ?? `Send failed: ${code}`;
|
|
30
|
+
return to ? template.replace(/\{to\}/g, to) : template;
|
|
31
|
+
}
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
18
33
|
// ConversationManager
|
|
19
34
|
// ---------------------------------------------------------------------------
|
|
20
35
|
export class ConversationManager {
|
|
21
|
-
sessionLifecycle;
|
|
22
36
|
client;
|
|
23
37
|
connectorHost;
|
|
24
|
-
/** Conversations keyed by
|
|
38
|
+
/** Conversations keyed by routable address */
|
|
25
39
|
conversations = new Map();
|
|
26
40
|
constructor(client, connectorHost) {
|
|
27
41
|
this.client = client;
|
|
28
42
|
this.connectorHost = connectorHost;
|
|
29
|
-
this.sessionLifecycle = new SessionLifecycle(client);
|
|
30
43
|
}
|
|
31
44
|
// -------------------------------------------------------------------------
|
|
32
45
|
// Public API — identity-based
|
|
33
46
|
// -------------------------------------------------------------------------
|
|
34
47
|
/**
|
|
35
|
-
* Send a message to a contact.
|
|
36
|
-
*
|
|
48
|
+
* Send a message to a contact. Sends directly to the resolved address —
|
|
49
|
+
* no session management needed.
|
|
37
50
|
*
|
|
38
|
-
*
|
|
51
|
+
* Returns a structured result with status and optional error.
|
|
52
|
+
* ConnectorError codes (ADDRESS_NOT_FOUND, ACCESS_DENIED, etc.) are
|
|
53
|
+
* mapped to human-readable messages for LLM tool results.
|
|
54
|
+
*
|
|
55
|
+
* @param contact - Handle, MSTP address, or passport address of the target.
|
|
39
56
|
* @param content - Message content to send.
|
|
40
57
|
*/
|
|
41
58
|
async send(contact, content) {
|
|
@@ -50,81 +67,62 @@ export class ConversationManager {
|
|
|
50
67
|
});
|
|
51
68
|
}
|
|
52
69
|
try {
|
|
53
|
-
const
|
|
54
|
-
const sent = this.client.sendMessage(sessionId, content, {
|
|
55
|
-
contentType: "text",
|
|
56
|
-
});
|
|
57
|
-
if (!sent) {
|
|
58
|
-
return {
|
|
59
|
-
status: "failed",
|
|
60
|
-
error: "Failed to send message. The network connection may be temporarily unavailable.",
|
|
61
|
-
};
|
|
62
|
-
}
|
|
70
|
+
const ack = await this.client.send(address, content, "text");
|
|
63
71
|
// Update lastMessageAt
|
|
64
72
|
const entry = this.conversations.get(address);
|
|
65
73
|
if (entry) {
|
|
66
74
|
entry.lastMessageAt = Date.now();
|
|
67
75
|
}
|
|
68
|
-
dbg("send contact=%s address=%s
|
|
76
|
+
dbg("send contact=%s address=%s status=%s", contact, address, ack.status);
|
|
69
77
|
return { status: "sent" };
|
|
70
78
|
}
|
|
71
79
|
catch (err) {
|
|
80
|
+
if (err instanceof ConnectorError) {
|
|
81
|
+
const message = formatErrorMessage(err.code, err.to ?? contact);
|
|
82
|
+
dbg("send failed contact=%s code=%s message=%s", contact, err.code, message);
|
|
83
|
+
return { status: "failed", error: message, errorCode: err.code };
|
|
84
|
+
}
|
|
72
85
|
const message = err instanceof Error ? err.message : "Unknown error";
|
|
73
86
|
dbg("send failed contact=%s error=%s", contact, message);
|
|
74
87
|
return { status: "failed", error: message };
|
|
75
88
|
}
|
|
76
89
|
}
|
|
77
90
|
/**
|
|
78
|
-
* Register an inbound
|
|
79
|
-
* Called by the channel adapter
|
|
91
|
+
* Register an inbound conversation (remote agent or visitor initiated).
|
|
92
|
+
* Called by the channel adapter when a message arrives from a new address.
|
|
80
93
|
*/
|
|
81
|
-
registerInbound(
|
|
82
|
-
this.
|
|
83
|
-
|
|
84
|
-
this.conversations.set(address, {
|
|
85
|
-
contact,
|
|
86
|
-
address,
|
|
87
|
-
lastMessageAt: Date.now(),
|
|
88
|
-
initiatedBy: "remote",
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
const entry = this.conversations.get(address);
|
|
93
|
-
if (entry) {
|
|
94
|
-
entry.lastMessageAt = Date.now();
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
dbg("registerInbound sessionId=%s contact=%s address=%s", sessionId, contact, address);
|
|
94
|
+
registerInbound(contact, address) {
|
|
95
|
+
this.ensureConversationEntry(contact, address, "remote");
|
|
96
|
+
dbg("registerInbound contact=%s address=%s", contact, address);
|
|
98
97
|
}
|
|
99
98
|
/**
|
|
100
|
-
* Resolve a
|
|
101
|
-
* Used by the inbound dispatcher to derive sender identity from
|
|
99
|
+
* Resolve a routable address to a contact handle.
|
|
100
|
+
* Used by the inbound dispatcher to derive sender identity from MESSAGE_RECEIVED.from.
|
|
102
101
|
*/
|
|
103
|
-
|
|
104
|
-
const address = this.sessionLifecycle.getAddressBySessionId(sessionId);
|
|
105
|
-
if (!address)
|
|
106
|
-
return undefined;
|
|
102
|
+
getContactByAddress(address) {
|
|
107
103
|
const entry = this.conversations.get(address);
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
104
|
+
if (entry)
|
|
105
|
+
return entry.contact;
|
|
106
|
+
// Try resolving — the address might be a full MSTP address while conversations
|
|
107
|
+
// are keyed by a different form. Extract handle as fallback.
|
|
108
|
+
for (const [, e] of this.conversations) {
|
|
109
|
+
if (e.address === address)
|
|
110
|
+
return e.contact;
|
|
111
|
+
}
|
|
112
|
+
return undefined;
|
|
116
113
|
}
|
|
117
114
|
/**
|
|
118
115
|
* List all conversations with metadata.
|
|
116
|
+
* `active` is always true for address-based protocol — there is no session
|
|
117
|
+
* lifecycle. Conversations persist until explicitly ended or Plugin restarts.
|
|
119
118
|
*/
|
|
120
119
|
listConversations() {
|
|
121
120
|
const result = [];
|
|
122
|
-
for (const [
|
|
123
|
-
const sessionId = this.sessionLifecycle.getSession(address);
|
|
121
|
+
for (const [, entry] of this.conversations) {
|
|
124
122
|
result.push({
|
|
125
123
|
contact: entry.contact,
|
|
126
124
|
address: entry.address,
|
|
127
|
-
active:
|
|
125
|
+
active: true,
|
|
128
126
|
lastMessageAt: entry.lastMessageAt,
|
|
129
127
|
initiatedBy: entry.initiatedBy,
|
|
130
128
|
});
|
|
@@ -144,50 +142,76 @@ export class ConversationManager {
|
|
|
144
142
|
}
|
|
145
143
|
/**
|
|
146
144
|
* End the conversation with a contact.
|
|
147
|
-
*
|
|
145
|
+
* Removes the conversation entry. No END_SESSION needed — the Connector
|
|
146
|
+
* manages connection lifecycle (idle timeout).
|
|
148
147
|
*/
|
|
149
148
|
endConversation(contact) {
|
|
150
149
|
const address = this.resolveAddress(contact);
|
|
151
|
-
this.sessionLifecycle.closeSession(address);
|
|
152
150
|
this.conversations.delete(address);
|
|
153
151
|
dbg("endConversation contact=%s address=%s", contact, address);
|
|
154
152
|
}
|
|
155
|
-
// NOTE: handleDisconnected() and handleSessionEnded() are NOT needed here.
|
|
156
|
-
// SessionLifecycle owns session state transitions via its own event subscriptions
|
|
157
|
-
// (session_ended, disconnected). Conversations persist across both events —
|
|
158
|
-
// sessions are recreated transparently on the next send().
|
|
159
153
|
// -------------------------------------------------------------------------
|
|
160
154
|
// Contact resolution
|
|
161
155
|
// -------------------------------------------------------------------------
|
|
162
156
|
/**
|
|
163
|
-
* Resolve a contact (handle or
|
|
157
|
+
* Resolve a contact (handle, MSTP address, or passport address) to a
|
|
158
|
+
* routable address.
|
|
164
159
|
*
|
|
165
160
|
* Resolution order:
|
|
166
|
-
* 1.
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
161
|
+
* 1. MSTP address (starts with mstps:// or mstp://) → return as-is.
|
|
162
|
+
* 2. Passport address (starts with passport:) → return as-is (already routable).
|
|
163
|
+
* 3. Already a key in the conversations map → return as-is.
|
|
164
|
+
* 4. Reverse lookup: if any existing conversation has this handle as its
|
|
165
|
+
* contact, use that conversation's address. This ensures replies to a
|
|
166
|
+
* cross-Connector sender route to the sender's original address, not to
|
|
167
|
+
* a locally-constructed address.
|
|
168
|
+
* 5. Otherwise treat as handle → construct `mstps://${connectorHost}/${handle}`.
|
|
171
169
|
*/
|
|
172
170
|
resolveAddress(contact) {
|
|
173
171
|
if (contact.startsWith("mstps://") || contact.startsWith("mstp://")) {
|
|
174
172
|
return contact;
|
|
175
173
|
}
|
|
176
|
-
|
|
177
|
-
|
|
174
|
+
if (contact.startsWith("passport:")) {
|
|
175
|
+
return contact;
|
|
176
|
+
}
|
|
178
177
|
if (this.conversations.has(contact)) {
|
|
179
178
|
return contact;
|
|
180
179
|
}
|
|
180
|
+
// Reverse lookup: handle → existing conversation address.
|
|
181
|
+
// Handles the case where inbound arrived from a remote Connector
|
|
182
|
+
// (e.g., "mstps://remote-host/mason") but the LLM replies using
|
|
183
|
+
// the bare handle "mason".
|
|
184
|
+
for (const [addr, entry] of this.conversations) {
|
|
185
|
+
if (entry.contact === contact)
|
|
186
|
+
return addr;
|
|
187
|
+
}
|
|
181
188
|
return `mstps://${this.connectorHost}/${contact}`;
|
|
182
189
|
}
|
|
183
190
|
/**
|
|
184
|
-
* Extract handle from
|
|
185
|
-
*
|
|
191
|
+
* Extract a display-friendly handle from any address scheme.
|
|
192
|
+
* Delegates to shared utility — single source of truth.
|
|
186
193
|
*/
|
|
187
194
|
extractHandle(address) {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
195
|
+
return extractHandleFromAddress(address);
|
|
196
|
+
}
|
|
197
|
+
// -------------------------------------------------------------------------
|
|
198
|
+
// Internal
|
|
199
|
+
// -------------------------------------------------------------------------
|
|
200
|
+
ensureConversationEntry(contact, address, initiatedBy) {
|
|
201
|
+
if (!this.conversations.has(address)) {
|
|
202
|
+
this.conversations.set(address, {
|
|
203
|
+
contact,
|
|
204
|
+
address,
|
|
205
|
+
lastMessageAt: Date.now(),
|
|
206
|
+
initiatedBy,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
const entry = this.conversations.get(address);
|
|
211
|
+
if (entry) {
|
|
212
|
+
entry.lastMessageAt = Date.now();
|
|
213
|
+
}
|
|
214
|
+
}
|
|
191
215
|
}
|
|
192
216
|
// -------------------------------------------------------------------------
|
|
193
217
|
// Test helpers
|
|
@@ -195,6 +219,5 @@ export class ConversationManager {
|
|
|
195
219
|
/** @internal Reset for test isolation. */
|
|
196
220
|
_resetForTesting() {
|
|
197
221
|
this.conversations.clear();
|
|
198
|
-
this.sessionLifecycle._resetForTesting();
|
|
199
222
|
}
|
|
200
223
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared handle extraction utility.
|
|
3
|
+
*
|
|
4
|
+
* Used by ConversationManager (contact resolution) and Channel (sender name derivation).
|
|
5
|
+
* Single source of truth for address → display handle mapping.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Extract a display-friendly handle from any address scheme.
|
|
9
|
+
*
|
|
10
|
+
* - `mstps://preview.masons.ai/alice` → `alice`
|
|
11
|
+
* - `passport:@luomingke` → `luomingke`
|
|
12
|
+
* - `passport:user_abc` → `user_abc`
|
|
13
|
+
* - `mason` → `mason` (bare handle passthrough)
|
|
14
|
+
*/
|
|
15
|
+
export declare function extractHandleFromAddress(address: string): string;
|
|
16
|
+
//# sourceMappingURL=handle-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handle-utils.d.ts","sourceRoot":"","sources":["../src/handle-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAUhE"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared handle extraction utility.
|
|
3
|
+
*
|
|
4
|
+
* Used by ConversationManager (contact resolution) and Channel (sender name derivation).
|
|
5
|
+
* Single source of truth for address → display handle mapping.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Extract a display-friendly handle from any address scheme.
|
|
9
|
+
*
|
|
10
|
+
* - `mstps://preview.masons.ai/alice` → `alice`
|
|
11
|
+
* - `passport:@luomingke` → `luomingke`
|
|
12
|
+
* - `passport:user_abc` → `user_abc`
|
|
13
|
+
* - `mason` → `mason` (bare handle passthrough)
|
|
14
|
+
*/
|
|
15
|
+
export function extractHandleFromAddress(address) {
|
|
16
|
+
if (address.startsWith("passport:@")) {
|
|
17
|
+
return address.slice("passport:@".length);
|
|
18
|
+
}
|
|
19
|
+
if (address.startsWith("passport:")) {
|
|
20
|
+
return address.slice("passport:".length);
|
|
21
|
+
}
|
|
22
|
+
const trimmed = address.replace(/\/+$/, "");
|
|
23
|
+
const parts = trimmed.split("/");
|
|
24
|
+
return parts[parts.length - 1] || address;
|
|
25
|
+
}
|
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 {
|
|
3
|
+
export type { AddressedMessageEvent, DeliveryPendingEvent, 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,
|
|
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,gBAAgB,EAChB,YAAY,EACZ,oBAAoB,GACrB,MAAM,YAAY,CAAC"}
|
|
@@ -1,31 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Owner
|
|
2
|
+
* Owner Identity State — tracks which addresses belong to the agent's owner.
|
|
3
3
|
*
|
|
4
4
|
* When the Connector detects that a Passport visitor is the agent's owner
|
|
5
|
-
* (deterministic userId comparison, #836), it
|
|
6
|
-
*
|
|
5
|
+
* (deterministic userId comparison, #836), it includes `is_owner: true` in
|
|
6
|
+
* MESSAGE_RECEIVED metadata. This module maintains the Plugin-side state:
|
|
7
7
|
*
|
|
8
|
-
* - `
|
|
9
|
-
* Populated on
|
|
8
|
+
* - `ownerAddresses`: Set of routable addresses where the visitor is the owner.
|
|
9
|
+
* Populated on first MESSAGE_RECEIVED with is_owner=true, cleared on disconnect.
|
|
10
10
|
*
|
|
11
11
|
* - `currentTurnIsOwner`: Per-turn flag set in the message_received handler
|
|
12
12
|
* and read in before_prompt_build. Reset after each read to avoid stale state.
|
|
13
|
-
* Race condition note (from design review): if two messages arrive on
|
|
14
|
-
* different sessions concurrently, the flag may reflect the wrong session.
|
|
15
|
-
* Fail-safe: owner gets the routing warning (same as today's behavior).
|
|
16
|
-
* Acceptable for Phase 1 — OpenClaw processes turns sequentially per agent.
|
|
17
13
|
*
|
|
18
14
|
* Module-level singleton — shared between channel.ts (write) and plugin.ts (read).
|
|
19
|
-
* Same pattern as owner-notes.ts.
|
|
20
15
|
*/
|
|
21
|
-
/** Mark
|
|
22
|
-
export declare function
|
|
23
|
-
/**
|
|
24
|
-
export declare function
|
|
25
|
-
/** Clear all owner
|
|
26
|
-
export declare function
|
|
27
|
-
/** Check if a session belongs to the owner. */
|
|
28
|
-
export declare function isOwnerSession(sessionId: string): boolean;
|
|
16
|
+
/** Mark an address as belonging to the owner. */
|
|
17
|
+
export declare function markOwnerAddress(address: string): void;
|
|
18
|
+
/** Check if an address belongs to the owner. */
|
|
19
|
+
export declare function isOwnerAddress(address: string): boolean;
|
|
20
|
+
/** Clear all owner state (connection lost — all addresses invalid). */
|
|
21
|
+
export declare function clearOwnerState(): void;
|
|
29
22
|
/**
|
|
30
23
|
* Set the per-turn owner flag. Called in message_received before dispatch.
|
|
31
24
|
* The flag is consumed (read + reset) by before_prompt_build.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"owner-session-state.d.ts","sourceRoot":"","sources":["../src/owner-session-state.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"owner-session-state.d.ts","sourceRoot":"","sources":["../src/owner-session-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAgBH,iDAAiD;AACjD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAEtD;AAED,gDAAgD;AAChD,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED,uEAAuE;AACvE,wBAAgB,eAAe,IAAI,IAAI,CAGtC;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAE1D;AAMD;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,OAAO,CAInD"}
|
|
@@ -1,50 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Owner
|
|
2
|
+
* Owner Identity State — tracks which addresses belong to the agent's owner.
|
|
3
3
|
*
|
|
4
4
|
* When the Connector detects that a Passport visitor is the agent's owner
|
|
5
|
-
* (deterministic userId comparison, #836), it
|
|
6
|
-
*
|
|
5
|
+
* (deterministic userId comparison, #836), it includes `is_owner: true` in
|
|
6
|
+
* MESSAGE_RECEIVED metadata. This module maintains the Plugin-side state:
|
|
7
7
|
*
|
|
8
|
-
* - `
|
|
9
|
-
* Populated on
|
|
8
|
+
* - `ownerAddresses`: Set of routable addresses where the visitor is the owner.
|
|
9
|
+
* Populated on first MESSAGE_RECEIVED with is_owner=true, cleared on disconnect.
|
|
10
10
|
*
|
|
11
11
|
* - `currentTurnIsOwner`: Per-turn flag set in the message_received handler
|
|
12
12
|
* and read in before_prompt_build. Reset after each read to avoid stale state.
|
|
13
|
-
* Race condition note (from design review): if two messages arrive on
|
|
14
|
-
* different sessions concurrently, the flag may reflect the wrong session.
|
|
15
|
-
* Fail-safe: owner gets the routing warning (same as today's behavior).
|
|
16
|
-
* Acceptable for Phase 1 — OpenClaw processes turns sequentially per agent.
|
|
17
13
|
*
|
|
18
14
|
* Module-level singleton — shared between channel.ts (write) and plugin.ts (read).
|
|
19
|
-
* Same pattern as owner-notes.ts.
|
|
20
15
|
*/
|
|
21
16
|
// ---------------------------------------------------------------------------
|
|
22
17
|
// State
|
|
23
18
|
// ---------------------------------------------------------------------------
|
|
24
|
-
/**
|
|
25
|
-
const
|
|
26
|
-
/** Whether the current LLM turn was triggered by an owner
|
|
19
|
+
/** Routable addresses where the visitor has been identified as the owner. */
|
|
20
|
+
const ownerAddresses = new Set();
|
|
21
|
+
/** Whether the current LLM turn was triggered by an owner. */
|
|
27
22
|
let currentTurnIsOwner = false;
|
|
28
23
|
// ---------------------------------------------------------------------------
|
|
29
24
|
// Write API (called from channel.ts)
|
|
30
25
|
// ---------------------------------------------------------------------------
|
|
31
|
-
/** Mark
|
|
32
|
-
export function
|
|
33
|
-
|
|
26
|
+
/** Mark an address as belonging to the owner. */
|
|
27
|
+
export function markOwnerAddress(address) {
|
|
28
|
+
ownerAddresses.add(address);
|
|
34
29
|
}
|
|
35
|
-
/**
|
|
36
|
-
export function
|
|
37
|
-
|
|
30
|
+
/** Check if an address belongs to the owner. */
|
|
31
|
+
export function isOwnerAddress(address) {
|
|
32
|
+
return ownerAddresses.has(address);
|
|
38
33
|
}
|
|
39
|
-
/** Clear all owner
|
|
40
|
-
export function
|
|
41
|
-
|
|
34
|
+
/** Clear all owner state (connection lost — all addresses invalid). */
|
|
35
|
+
export function clearOwnerState() {
|
|
36
|
+
ownerAddresses.clear();
|
|
42
37
|
currentTurnIsOwner = false;
|
|
43
38
|
}
|
|
44
|
-
/** Check if a session belongs to the owner. */
|
|
45
|
-
export function isOwnerSession(sessionId) {
|
|
46
|
-
return ownerSessionIds.has(sessionId);
|
|
47
|
-
}
|
|
48
39
|
/**
|
|
49
40
|
* Set the per-turn owner flag. Called in message_received before dispatch.
|
|
50
41
|
* The flag is consumed (read + reset) by before_prompt_build.
|
package/dist/tools.d.ts
CHANGED
|
@@ -15,8 +15,7 @@
|
|
|
15
15
|
* Session Abstraction (#741):
|
|
16
16
|
* - `masons_send_message(to, content)` — sends via ConversationManager
|
|
17
17
|
* - `masons_end_conversation(contact)` — ends via ConversationManager
|
|
18
|
-
*
|
|
19
|
-
* - `masons_end_session` — DEPRECATED SHIM (one release cycle)
|
|
18
|
+
* (Deprecated shims masons_create_session and masons_end_session have been removed.)
|
|
20
19
|
*/
|
|
21
20
|
interface ToolContent {
|
|
22
21
|
content: Array<{
|
package/dist/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AA4CH,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,OAAO;IACf,YAAY,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;CACzE;AA0CD,uDAAuD;AACvD,wBAAgB,qBAAqB,IAAI,IAAI,CAI5C;AAsFD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAszBhD"}
|
package/dist/tools.js
CHANGED
|
@@ -15,15 +15,14 @@
|
|
|
15
15
|
* Session Abstraction (#741):
|
|
16
16
|
* - `masons_send_message(to, content)` — sends via ConversationManager
|
|
17
17
|
* - `masons_end_conversation(contact)` — ends via ConversationManager
|
|
18
|
-
*
|
|
19
|
-
* - `masons_end_session` — DEPRECATED SHIM (one release cycle)
|
|
18
|
+
* (Deprecated shims masons_create_session and masons_end_session have been removed.)
|
|
20
19
|
*/
|
|
21
20
|
import { tmpdir } from "node:os";
|
|
22
21
|
import { Type } from "@sinclair/typebox";
|
|
23
22
|
import { clearTargetHandle, getOpenClawHome, getPendingTarget, isProfileNeeded, markProfileComplete, markProfileNeeded, requireApiKey, requireConversationManager, requirePlatformConfig, writeCredentials, } from "./config.js";
|
|
24
23
|
import { ownerNotesQueue } from "./owner-notes.js";
|
|
25
|
-
import { sentMessageBuffer } from "./sent-message-buffer.js";
|
|
26
24
|
import { acceptRequest, declineRequest, getConnectionStatus, initSetup, listConnections, listRequests, onboard, PlatformApiError, pollSetup, reconnect, requestConnection, SetupExpiredError, SetupPendingError, updateProfile, } from "./platform-client.js";
|
|
25
|
+
import { sentMessageBuffer } from "./sent-message-buffer.js";
|
|
27
26
|
import { fetchLatestVersion, getPluginVersion, getUpdateInfo, } from "./update-check.js";
|
|
28
27
|
// ---------------------------------------------------------------------------
|
|
29
28
|
// Constants
|
|
@@ -750,34 +749,4 @@ export function registerTools(api) {
|
|
|
750
749
|
].join("\n"));
|
|
751
750
|
},
|
|
752
751
|
});
|
|
753
|
-
// =========================================================================
|
|
754
|
-
// DEPRECATED SHIMS — kept for one release cycle for backward compatibility
|
|
755
|
-
// =========================================================================
|
|
756
|
-
// --- masons_create_session (DEPRECATED) -----------------------------------
|
|
757
|
-
api.registerTool({
|
|
758
|
-
name: "masons_create_session",
|
|
759
|
-
description: "[DEPRECATED — sessions are now automatic. Use masons_send_message directly.] Start a conversation with another Agent.",
|
|
760
|
-
parameters: Type.Object({
|
|
761
|
-
target: Type.String({
|
|
762
|
-
description: "Network address of the agent (e.g. mstps://preview.masons.ai/alice)",
|
|
763
|
-
}),
|
|
764
|
-
}),
|
|
765
|
-
// Intentionally ignores params — this shim just redirects the LLM to the new tool.
|
|
766
|
-
execute: withUpdateNotice(async () => {
|
|
767
|
-
return textResult("Sessions are now managed automatically. Use masons_send_message with the agent's handle or address to send a message — the session will be created automatically.");
|
|
768
|
-
}),
|
|
769
|
-
}, { optional: true });
|
|
770
|
-
// --- masons_end_session (DEPRECATED) --------------------------------------
|
|
771
|
-
api.registerTool({
|
|
772
|
-
name: "masons_end_session",
|
|
773
|
-
description: "[DEPRECATED — use masons_end_conversation instead.] End a conversation session.",
|
|
774
|
-
parameters: Type.Object({
|
|
775
|
-
sessionId: Type.String({
|
|
776
|
-
description: "Session ID of the session to end",
|
|
777
|
-
}),
|
|
778
|
-
}),
|
|
779
|
-
execute: withUpdateNotice(async () => {
|
|
780
|
-
return textResult("This tool is deprecated. Use masons_end_conversation with the agent's handle instead.");
|
|
781
|
-
}),
|
|
782
|
-
}, { optional: true });
|
|
783
752
|
}
|