@xfxstudio/claworld 2026.4.27-testing.1 → 2026.4.28-testing.1
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/openclaw.plugin.json +245 -234
- package/package.json +1 -1
- package/src/openclaw/index.js +1 -0
- package/src/openclaw/plugin/account-identity.js +2 -5
- package/src/openclaw/plugin/claworld-channel-plugin.js +140 -2
- package/src/openclaw/plugin/config-schema.js +6 -0
- package/src/openclaw/plugin/managed-config.js +1 -4
- package/src/openclaw/plugin/register.js +69 -33
- package/src/openclaw/plugin/relay-client.js +16 -0
- package/src/openclaw/runtime/product-shell-helper.js +2 -1
- package/src/openclaw/runtime/tool-contracts.js +1 -1
- package/src/openclaw/runtime/world-moderation-helper.js +192 -0
package/openclaw.plugin.json
CHANGED
|
@@ -8,284 +8,295 @@
|
|
|
8
8
|
],
|
|
9
9
|
"name": "Claworld Persona Relay",
|
|
10
10
|
"description": "Claworld relay world channel plugin for OpenClaw.",
|
|
11
|
-
"version": "2026.4.
|
|
11
|
+
"version": "2026.4.28-testing.1",
|
|
12
12
|
"configSchema": {
|
|
13
13
|
"type": "object",
|
|
14
14
|
"additionalProperties": false,
|
|
15
|
-
"properties": {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
"type": "boolean",
|
|
23
|
-
"description": "Enable the Claworld channel plugin."
|
|
24
|
-
},
|
|
25
|
-
"serverUrl": {
|
|
26
|
-
"type": "string",
|
|
27
|
-
"minLength": 1,
|
|
28
|
-
"description": "Relay backend base URL or websocket URL (http/https/ws/wss)."
|
|
29
|
-
},
|
|
30
|
-
"apiKey": {
|
|
31
|
-
"type": "string",
|
|
32
|
-
"minLength": 1,
|
|
33
|
-
"description": "Plugin/backend API key for future backend-authenticated control paths."
|
|
34
|
-
},
|
|
35
|
-
"appToken": {
|
|
36
|
-
"type": "string",
|
|
37
|
-
"minLength": 1,
|
|
38
|
-
"description": "Canonical Claworld app token for this channel account."
|
|
39
|
-
},
|
|
40
|
-
"accountId": {
|
|
41
|
-
"type": "string",
|
|
42
|
-
"minLength": 1,
|
|
43
|
-
"description": "Local OpenClaw-facing account id bound to this channel instance."
|
|
44
|
-
},
|
|
45
|
-
"toolProfile": {
|
|
46
|
-
"type": "string",
|
|
47
|
-
"enum": [
|
|
48
|
-
"minimal",
|
|
49
|
-
"default",
|
|
50
|
-
"world",
|
|
51
|
-
"full"
|
|
52
|
-
],
|
|
53
|
-
"description": "Optional ignored profile selector. Current tool exposure is backend-defined."
|
|
54
|
-
},
|
|
55
|
-
"heartbeatSeconds": {
|
|
56
|
-
"type": "integer",
|
|
57
|
-
"minimum": 1,
|
|
58
|
-
"description": "Heartbeat cadence for the relay websocket client.",
|
|
59
|
-
"default": 15
|
|
60
|
-
},
|
|
61
|
-
"reconnect": {
|
|
62
|
-
"type": "boolean",
|
|
63
|
-
"description": "Whether reconnect attempts are allowed after disconnect.",
|
|
64
|
-
"default": true
|
|
65
|
-
},
|
|
66
|
-
"routing": {
|
|
15
|
+
"properties": {}
|
|
16
|
+
},
|
|
17
|
+
"channelConfigs": {
|
|
18
|
+
"claworld": {
|
|
19
|
+
"label": "Claworld",
|
|
20
|
+
"description": "Claworld relay world channel configuration.",
|
|
21
|
+
"schema": {
|
|
67
22
|
"type": "object",
|
|
68
23
|
"additionalProperties": false,
|
|
69
24
|
"properties": {
|
|
70
|
-
"
|
|
25
|
+
"name": {
|
|
71
26
|
"type": "string",
|
|
72
|
-
"
|
|
73
|
-
|
|
74
|
-
"mainagent"
|
|
75
|
-
],
|
|
76
|
-
"default": "mainagent"
|
|
77
|
-
},
|
|
78
|
-
"fallbackTarget": {
|
|
79
|
-
"type": "string",
|
|
80
|
-
"enum": [
|
|
81
|
-
"mainagent",
|
|
82
|
-
"human(optional)"
|
|
83
|
-
],
|
|
84
|
-
"default": "mainagent"
|
|
27
|
+
"minLength": 1,
|
|
28
|
+
"description": "Optional operator-facing name for this local Claworld account."
|
|
85
29
|
},
|
|
86
|
-
"allowHumanInterrupt": {
|
|
87
|
-
"type": "boolean",
|
|
88
|
-
"default": true
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
},
|
|
92
|
-
"testing": {
|
|
93
|
-
"type": "object",
|
|
94
|
-
"additionalProperties": false,
|
|
95
|
-
"properties": {
|
|
96
|
-
"allowBridgedCommandDispatch": {
|
|
97
|
-
"type": "boolean",
|
|
98
|
-
"description": "Test-only switch that allows bridged relay turns beginning with slash commands to use the OpenClaw command fast-path.",
|
|
99
|
-
"default": false
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
},
|
|
103
|
-
"registration": {
|
|
104
|
-
"type": "object",
|
|
105
|
-
"additionalProperties": false,
|
|
106
|
-
"properties": {
|
|
107
30
|
"enabled": {
|
|
108
31
|
"type": "boolean",
|
|
109
|
-
"description": "Enable
|
|
110
|
-
"default": false
|
|
32
|
+
"description": "Enable the Claworld channel plugin."
|
|
111
33
|
},
|
|
112
|
-
"
|
|
34
|
+
"serverUrl": {
|
|
113
35
|
"type": "string",
|
|
114
36
|
"minLength": 1,
|
|
115
|
-
"description": "
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
},
|
|
119
|
-
"relay": {
|
|
120
|
-
"type": "object",
|
|
121
|
-
"additionalProperties": false,
|
|
122
|
-
"properties": {
|
|
123
|
-
"appToken": {
|
|
37
|
+
"description": "Relay backend base URL or websocket URL (http/https/ws/wss)."
|
|
38
|
+
},
|
|
39
|
+
"apiKey": {
|
|
124
40
|
"type": "string",
|
|
125
41
|
"minLength": 1,
|
|
126
|
-
"description": "
|
|
42
|
+
"description": "Plugin/backend API key for future backend-authenticated control paths."
|
|
127
43
|
},
|
|
128
|
-
"
|
|
44
|
+
"appToken": {
|
|
129
45
|
"type": "string",
|
|
130
46
|
"minLength": 1,
|
|
131
|
-
"description": "
|
|
47
|
+
"description": "Canonical Claworld app token for this channel account."
|
|
132
48
|
},
|
|
133
|
-
"
|
|
49
|
+
"accountId": {
|
|
134
50
|
"type": "string",
|
|
135
51
|
"minLength": 1,
|
|
136
|
-
"description": "
|
|
52
|
+
"description": "Local OpenClaw-facing account id bound to this channel instance."
|
|
137
53
|
},
|
|
138
|
-
"
|
|
54
|
+
"toolProfile": {
|
|
55
|
+
"type": "string",
|
|
56
|
+
"enum": [
|
|
57
|
+
"minimal",
|
|
58
|
+
"default",
|
|
59
|
+
"world",
|
|
60
|
+
"full"
|
|
61
|
+
],
|
|
62
|
+
"description": "Optional ignored profile selector. Current tool exposure is backend-defined."
|
|
63
|
+
},
|
|
64
|
+
"heartbeatSeconds": {
|
|
65
|
+
"type": "integer",
|
|
66
|
+
"minimum": 1,
|
|
67
|
+
"description": "Heartbeat cadence for the relay websocket client.",
|
|
68
|
+
"default": 15
|
|
69
|
+
},
|
|
70
|
+
"reconnect": {
|
|
71
|
+
"type": "boolean",
|
|
72
|
+
"description": "Whether reconnect attempts are allowed after disconnect.",
|
|
73
|
+
"default": true
|
|
74
|
+
},
|
|
75
|
+
"routing": {
|
|
76
|
+
"type": "object",
|
|
77
|
+
"additionalProperties": false,
|
|
78
|
+
"properties": {
|
|
79
|
+
"sessionTarget": {
|
|
80
|
+
"type": "string",
|
|
81
|
+
"enum": [
|
|
82
|
+
"subagent",
|
|
83
|
+
"mainagent"
|
|
84
|
+
],
|
|
85
|
+
"default": "mainagent"
|
|
86
|
+
},
|
|
87
|
+
"fallbackTarget": {
|
|
88
|
+
"type": "string",
|
|
89
|
+
"enum": [
|
|
90
|
+
"mainagent",
|
|
91
|
+
"human(optional)"
|
|
92
|
+
],
|
|
93
|
+
"default": "mainagent"
|
|
94
|
+
},
|
|
95
|
+
"allowHumanInterrupt": {
|
|
96
|
+
"type": "boolean",
|
|
97
|
+
"default": true
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
"testing": {
|
|
102
|
+
"type": "object",
|
|
103
|
+
"additionalProperties": false,
|
|
104
|
+
"properties": {
|
|
105
|
+
"allowBridgedCommandDispatch": {
|
|
106
|
+
"type": "boolean",
|
|
107
|
+
"description": "Test-only switch that allows bridged relay turns beginning with slash commands to use the OpenClaw command fast-path.",
|
|
108
|
+
"default": false
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"registration": {
|
|
113
|
+
"type": "object",
|
|
114
|
+
"additionalProperties": false,
|
|
115
|
+
"properties": {
|
|
116
|
+
"enabled": {
|
|
117
|
+
"type": "boolean",
|
|
118
|
+
"description": "Enable relay agent registration when this account does not already have an app token.",
|
|
119
|
+
"default": false
|
|
120
|
+
},
|
|
121
|
+
"displayName": {
|
|
122
|
+
"type": "string",
|
|
123
|
+
"minLength": 1,
|
|
124
|
+
"description": "Public display name to use when the relay agent is created or refreshed."
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
"relay": {
|
|
129
|
+
"type": "object",
|
|
130
|
+
"additionalProperties": false,
|
|
131
|
+
"properties": {
|
|
132
|
+
"appToken": {
|
|
133
|
+
"type": "string",
|
|
134
|
+
"minLength": 1,
|
|
135
|
+
"description": "Canonical Claworld app token for this account. The runtime resolves the bound relay agent from this token."
|
|
136
|
+
},
|
|
137
|
+
"agentId": {
|
|
138
|
+
"type": "string",
|
|
139
|
+
"minLength": 1,
|
|
140
|
+
"description": "Optional relay agent id hint. The current flow resolves the binding from appToken at runtime."
|
|
141
|
+
},
|
|
142
|
+
"credentialToken": {
|
|
143
|
+
"type": "string",
|
|
144
|
+
"minLength": 1,
|
|
145
|
+
"description": "Optional credential token for this account. appToken is the current field."
|
|
146
|
+
},
|
|
147
|
+
"defaultTargetAgentId": {
|
|
148
|
+
"type": "string",
|
|
149
|
+
"minLength": 1,
|
|
150
|
+
"description": "Default relay target agentId for minimal outbound testing."
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
"defaultAccount": {
|
|
139
155
|
"type": "string",
|
|
140
156
|
"minLength": 1,
|
|
141
|
-
"description": "Default
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
"minLength": 1,
|
|
148
|
-
"description": "Default account id to use when multiple claworld accounts are configured."
|
|
149
|
-
},
|
|
150
|
-
"accounts": {
|
|
151
|
-
"type": "object",
|
|
152
|
-
"minProperties": 1,
|
|
153
|
-
"additionalProperties": {
|
|
154
|
-
"type": "object",
|
|
155
|
-
"additionalProperties": false,
|
|
156
|
-
"required": [
|
|
157
|
-
"enabled",
|
|
158
|
-
"serverUrl",
|
|
159
|
-
"apiKey",
|
|
160
|
-
"accountId"
|
|
161
|
-
],
|
|
162
|
-
"properties": {
|
|
163
|
-
"name": {
|
|
164
|
-
"type": "string",
|
|
165
|
-
"minLength": 1,
|
|
166
|
-
"description": "Optional operator-facing name for this local Claworld account."
|
|
167
|
-
},
|
|
168
|
-
"enabled": {
|
|
169
|
-
"type": "boolean",
|
|
170
|
-
"description": "Enable the Claworld channel plugin."
|
|
171
|
-
},
|
|
172
|
-
"serverUrl": {
|
|
173
|
-
"type": "string",
|
|
174
|
-
"minLength": 1,
|
|
175
|
-
"description": "Relay backend base URL or websocket URL (http/https/ws/wss)."
|
|
176
|
-
},
|
|
177
|
-
"apiKey": {
|
|
178
|
-
"type": "string",
|
|
179
|
-
"minLength": 1,
|
|
180
|
-
"description": "Plugin/backend API key for future backend-authenticated control paths."
|
|
181
|
-
},
|
|
182
|
-
"appToken": {
|
|
183
|
-
"type": "string",
|
|
184
|
-
"minLength": 1,
|
|
185
|
-
"description": "Canonical Claworld app token for this channel account."
|
|
186
|
-
},
|
|
187
|
-
"accountId": {
|
|
188
|
-
"type": "string",
|
|
189
|
-
"minLength": 1,
|
|
190
|
-
"description": "Local OpenClaw-facing account id bound to this channel instance."
|
|
191
|
-
},
|
|
192
|
-
"toolProfile": {
|
|
193
|
-
"type": "string",
|
|
194
|
-
"enum": [
|
|
195
|
-
"minimal",
|
|
196
|
-
"default",
|
|
197
|
-
"world",
|
|
198
|
-
"full"
|
|
199
|
-
],
|
|
200
|
-
"description": "Optional ignored profile selector. Current tool exposure is backend-defined."
|
|
201
|
-
},
|
|
202
|
-
"heartbeatSeconds": {
|
|
203
|
-
"type": "integer",
|
|
204
|
-
"minimum": 1,
|
|
205
|
-
"description": "Heartbeat cadence for the relay websocket client.",
|
|
206
|
-
"default": 15
|
|
207
|
-
},
|
|
208
|
-
"reconnect": {
|
|
209
|
-
"type": "boolean",
|
|
210
|
-
"description": "Whether reconnect attempts are allowed after disconnect.",
|
|
211
|
-
"default": true
|
|
212
|
-
},
|
|
213
|
-
"routing": {
|
|
157
|
+
"description": "Default account id to use when multiple claworld accounts are configured."
|
|
158
|
+
},
|
|
159
|
+
"accounts": {
|
|
160
|
+
"type": "object",
|
|
161
|
+
"minProperties": 1,
|
|
162
|
+
"additionalProperties": {
|
|
214
163
|
"type": "object",
|
|
215
164
|
"additionalProperties": false,
|
|
165
|
+
"required": [
|
|
166
|
+
"enabled",
|
|
167
|
+
"serverUrl",
|
|
168
|
+
"apiKey",
|
|
169
|
+
"accountId"
|
|
170
|
+
],
|
|
216
171
|
"properties": {
|
|
217
|
-
"
|
|
218
|
-
"type": "string",
|
|
219
|
-
"enum": [
|
|
220
|
-
"subagent",
|
|
221
|
-
"mainagent"
|
|
222
|
-
],
|
|
223
|
-
"default": "mainagent"
|
|
224
|
-
},
|
|
225
|
-
"fallbackTarget": {
|
|
172
|
+
"name": {
|
|
226
173
|
"type": "string",
|
|
227
|
-
"
|
|
228
|
-
|
|
229
|
-
"human(optional)"
|
|
230
|
-
],
|
|
231
|
-
"default": "mainagent"
|
|
174
|
+
"minLength": 1,
|
|
175
|
+
"description": "Optional operator-facing name for this local Claworld account."
|
|
232
176
|
},
|
|
233
|
-
"allowHumanInterrupt": {
|
|
234
|
-
"type": "boolean",
|
|
235
|
-
"default": true
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
},
|
|
239
|
-
"testing": {
|
|
240
|
-
"type": "object",
|
|
241
|
-
"additionalProperties": false,
|
|
242
|
-
"properties": {
|
|
243
|
-
"allowBridgedCommandDispatch": {
|
|
244
|
-
"type": "boolean",
|
|
245
|
-
"description": "Test-only switch that allows bridged relay turns beginning with slash commands to use the OpenClaw command fast-path.",
|
|
246
|
-
"default": false
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
},
|
|
250
|
-
"registration": {
|
|
251
|
-
"type": "object",
|
|
252
|
-
"additionalProperties": false,
|
|
253
|
-
"properties": {
|
|
254
177
|
"enabled": {
|
|
255
178
|
"type": "boolean",
|
|
256
|
-
"description": "Enable
|
|
257
|
-
"default": false
|
|
179
|
+
"description": "Enable the Claworld channel plugin."
|
|
258
180
|
},
|
|
259
|
-
"
|
|
181
|
+
"serverUrl": {
|
|
260
182
|
"type": "string",
|
|
261
183
|
"minLength": 1,
|
|
262
|
-
"description": "
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
},
|
|
266
|
-
"relay": {
|
|
267
|
-
"type": "object",
|
|
268
|
-
"additionalProperties": false,
|
|
269
|
-
"properties": {
|
|
270
|
-
"appToken": {
|
|
184
|
+
"description": "Relay backend base URL or websocket URL (http/https/ws/wss)."
|
|
185
|
+
},
|
|
186
|
+
"apiKey": {
|
|
271
187
|
"type": "string",
|
|
272
188
|
"minLength": 1,
|
|
273
|
-
"description": "
|
|
189
|
+
"description": "Plugin/backend API key for future backend-authenticated control paths."
|
|
274
190
|
},
|
|
275
|
-
"
|
|
191
|
+
"appToken": {
|
|
276
192
|
"type": "string",
|
|
277
193
|
"minLength": 1,
|
|
278
|
-
"description": "
|
|
194
|
+
"description": "Canonical Claworld app token for this channel account."
|
|
279
195
|
},
|
|
280
|
-
"
|
|
196
|
+
"accountId": {
|
|
281
197
|
"type": "string",
|
|
282
198
|
"minLength": 1,
|
|
283
|
-
"description": "
|
|
199
|
+
"description": "Local OpenClaw-facing account id bound to this channel instance."
|
|
284
200
|
},
|
|
285
|
-
"
|
|
201
|
+
"toolProfile": {
|
|
286
202
|
"type": "string",
|
|
287
|
-
"
|
|
288
|
-
|
|
203
|
+
"enum": [
|
|
204
|
+
"minimal",
|
|
205
|
+
"default",
|
|
206
|
+
"world",
|
|
207
|
+
"full"
|
|
208
|
+
],
|
|
209
|
+
"description": "Optional ignored profile selector. Current tool exposure is backend-defined."
|
|
210
|
+
},
|
|
211
|
+
"heartbeatSeconds": {
|
|
212
|
+
"type": "integer",
|
|
213
|
+
"minimum": 1,
|
|
214
|
+
"description": "Heartbeat cadence for the relay websocket client.",
|
|
215
|
+
"default": 15
|
|
216
|
+
},
|
|
217
|
+
"reconnect": {
|
|
218
|
+
"type": "boolean",
|
|
219
|
+
"description": "Whether reconnect attempts are allowed after disconnect.",
|
|
220
|
+
"default": true
|
|
221
|
+
},
|
|
222
|
+
"routing": {
|
|
223
|
+
"type": "object",
|
|
224
|
+
"additionalProperties": false,
|
|
225
|
+
"properties": {
|
|
226
|
+
"sessionTarget": {
|
|
227
|
+
"type": "string",
|
|
228
|
+
"enum": [
|
|
229
|
+
"subagent",
|
|
230
|
+
"mainagent"
|
|
231
|
+
],
|
|
232
|
+
"default": "mainagent"
|
|
233
|
+
},
|
|
234
|
+
"fallbackTarget": {
|
|
235
|
+
"type": "string",
|
|
236
|
+
"enum": [
|
|
237
|
+
"mainagent",
|
|
238
|
+
"human(optional)"
|
|
239
|
+
],
|
|
240
|
+
"default": "mainagent"
|
|
241
|
+
},
|
|
242
|
+
"allowHumanInterrupt": {
|
|
243
|
+
"type": "boolean",
|
|
244
|
+
"default": true
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
"testing": {
|
|
249
|
+
"type": "object",
|
|
250
|
+
"additionalProperties": false,
|
|
251
|
+
"properties": {
|
|
252
|
+
"allowBridgedCommandDispatch": {
|
|
253
|
+
"type": "boolean",
|
|
254
|
+
"description": "Test-only switch that allows bridged relay turns beginning with slash commands to use the OpenClaw command fast-path.",
|
|
255
|
+
"default": false
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
"registration": {
|
|
260
|
+
"type": "object",
|
|
261
|
+
"additionalProperties": false,
|
|
262
|
+
"properties": {
|
|
263
|
+
"enabled": {
|
|
264
|
+
"type": "boolean",
|
|
265
|
+
"description": "Enable relay agent registration when this account does not already have an app token.",
|
|
266
|
+
"default": false
|
|
267
|
+
},
|
|
268
|
+
"displayName": {
|
|
269
|
+
"type": "string",
|
|
270
|
+
"minLength": 1,
|
|
271
|
+
"description": "Public display name to use when the relay agent is created or refreshed."
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
"relay": {
|
|
276
|
+
"type": "object",
|
|
277
|
+
"additionalProperties": false,
|
|
278
|
+
"properties": {
|
|
279
|
+
"appToken": {
|
|
280
|
+
"type": "string",
|
|
281
|
+
"minLength": 1,
|
|
282
|
+
"description": "Canonical Claworld app token for this account. The runtime resolves the bound relay agent from this token."
|
|
283
|
+
},
|
|
284
|
+
"agentId": {
|
|
285
|
+
"type": "string",
|
|
286
|
+
"minLength": 1,
|
|
287
|
+
"description": "Optional relay agent id hint. The current flow resolves the binding from appToken at runtime."
|
|
288
|
+
},
|
|
289
|
+
"credentialToken": {
|
|
290
|
+
"type": "string",
|
|
291
|
+
"minLength": 1,
|
|
292
|
+
"description": "Optional credential token for this account. appToken is the current field."
|
|
293
|
+
},
|
|
294
|
+
"defaultTargetAgentId": {
|
|
295
|
+
"type": "string",
|
|
296
|
+
"minLength": 1,
|
|
297
|
+
"description": "Default relay target agentId for minimal outbound testing."
|
|
298
|
+
}
|
|
299
|
+
}
|
|
289
300
|
}
|
|
290
301
|
}
|
|
291
302
|
}
|
package/package.json
CHANGED
package/src/openclaw/index.js
CHANGED
|
@@ -13,16 +13,13 @@ export function normalizeRuntimeRegistration(candidate = {}) {
|
|
|
13
13
|
const registration = candidate.registration && typeof candidate.registration === 'object'
|
|
14
14
|
? candidate.registration
|
|
15
15
|
: {};
|
|
16
|
-
const
|
|
17
|
-
? candidate.localAgent
|
|
18
|
-
: {};
|
|
19
|
-
const enabled = registration.enabled === true || legacyLocalAgent.enabled === true;
|
|
16
|
+
const enabled = registration.enabled === true;
|
|
20
17
|
|
|
21
18
|
if (!enabled) return { enabled: false };
|
|
22
19
|
|
|
23
20
|
return {
|
|
24
21
|
enabled: true,
|
|
25
|
-
displayName: normalizeText(registration.displayName,
|
|
22
|
+
displayName: normalizeText(registration.displayName, null),
|
|
26
23
|
};
|
|
27
24
|
}
|
|
28
25
|
|
|
@@ -35,8 +35,11 @@ import { createDemoSessionBootstrap } from '../runtime/demo-session-bootstrap.js
|
|
|
35
35
|
import {
|
|
36
36
|
broadcastModeratedWorld,
|
|
37
37
|
createModeratedWorld,
|
|
38
|
+
fetchModeratedWorldInvites,
|
|
38
39
|
fetchOwnedWorlds,
|
|
40
|
+
inviteModeratedWorldMember,
|
|
39
41
|
manageModeratedWorld,
|
|
42
|
+
revokeModeratedWorldInvite,
|
|
40
43
|
} from '../runtime/world-moderation-helper.js';
|
|
41
44
|
import {
|
|
42
45
|
fetchWorldMembership,
|
|
@@ -809,6 +812,48 @@ async function rejectChatRequest({
|
|
|
809
812
|
return result.body || {};
|
|
810
813
|
}
|
|
811
814
|
|
|
815
|
+
async function closeConversation({
|
|
816
|
+
runtimeConfig,
|
|
817
|
+
actorAgentId,
|
|
818
|
+
conversationKey = null,
|
|
819
|
+
localSessionKey = null,
|
|
820
|
+
localAgentId = null,
|
|
821
|
+
fetchImpl,
|
|
822
|
+
}) {
|
|
823
|
+
const relayLocalSessionKey = stripAgentScopedLocalSessionKey({
|
|
824
|
+
sessionKey: localSessionKey,
|
|
825
|
+
localAgentId,
|
|
826
|
+
});
|
|
827
|
+
const baseUrl = normalizeRelayHttpBaseUrl(runtimeConfig.serverUrl);
|
|
828
|
+
const result = await fetchJson(fetchImpl, `${baseUrl}/v1/chat-requests/conversations/close`, {
|
|
829
|
+
method: 'POST',
|
|
830
|
+
headers: {
|
|
831
|
+
'content-type': 'application/json',
|
|
832
|
+
...(runtimeConfig.apiKey ? { 'x-api-key': runtimeConfig.apiKey } : {}),
|
|
833
|
+
...buildRuntimeAuthHeaders(runtimeConfig),
|
|
834
|
+
},
|
|
835
|
+
body: JSON.stringify({
|
|
836
|
+
actorAgentId,
|
|
837
|
+
...(normalizeClaworldText(conversationKey, null) ? { conversationKey: normalizeClaworldText(conversationKey, null) } : {}),
|
|
838
|
+
...(normalizeClaworldText(relayLocalSessionKey, null) ? { localSessionKey: normalizeClaworldText(relayLocalSessionKey, null) } : {}),
|
|
839
|
+
}),
|
|
840
|
+
});
|
|
841
|
+
if (!result.ok) {
|
|
842
|
+
createRelayRouteError({
|
|
843
|
+
result,
|
|
844
|
+
runtimeConfig,
|
|
845
|
+
code: 'conversation_close_failed',
|
|
846
|
+
publicMessage: 'failed to close conversation',
|
|
847
|
+
context: {
|
|
848
|
+
actorAgentId,
|
|
849
|
+
conversationKey: normalizeClaworldText(conversationKey, null),
|
|
850
|
+
localSessionKey: relayLocalSessionKey,
|
|
851
|
+
},
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
return normalizeChatInboxPayloadSessionKeys(result.body || {}, { localAgentId });
|
|
855
|
+
}
|
|
856
|
+
|
|
812
857
|
function waitForAbort(signal) {
|
|
813
858
|
return new Promise((resolve) => {
|
|
814
859
|
if (!signal) return resolve({ reason: 'missing_abort_signal' });
|
|
@@ -1313,7 +1358,7 @@ async function resolveRelayAgentSummary({
|
|
|
1313
1358
|
|
|
1314
1359
|
return {
|
|
1315
1360
|
agentId: normalizedAgentId,
|
|
1316
|
-
displayName: normalizeClaworldText(runtimeConfig.registration?.displayName,
|
|
1361
|
+
displayName: normalizeClaworldText(runtimeConfig.registration?.displayName, null),
|
|
1317
1362
|
publicIdentity: null,
|
|
1318
1363
|
discoverable: null,
|
|
1319
1364
|
contactable: null,
|
|
@@ -1628,7 +1673,7 @@ async function fetchRuntimeWorldMembers({
|
|
|
1628
1673
|
}
|
|
1629
1674
|
const baseUrl = normalizeRelayHttpBaseUrl(runtimeConfig.serverUrl);
|
|
1630
1675
|
const requestUrl = new URL(`${baseUrl}/v1/worlds/${encodeURIComponent(normalizedWorldId)}/memberships`);
|
|
1631
|
-
if (agentId) requestUrl.searchParams.set('
|
|
1676
|
+
if (agentId) requestUrl.searchParams.set('actorAgentId', agentId);
|
|
1632
1677
|
if (status) requestUrl.searchParams.set('status', status);
|
|
1633
1678
|
const normalizedLimit = normalizeClaworldInteger(limit, null);
|
|
1634
1679
|
if (normalizedLimit > 0) requestUrl.searchParams.set('limit', String(normalizedLimit));
|
|
@@ -3303,6 +3348,17 @@ async function generateRuntimeProfileCard(context = {}) {
|
|
|
3303
3348
|
fetchImpl,
|
|
3304
3349
|
});
|
|
3305
3350
|
},
|
|
3351
|
+
closeConversation: async (context = {}) => {
|
|
3352
|
+
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
3353
|
+
return closeConversation({
|
|
3354
|
+
runtimeConfig: resolvedContext.runtimeConfig,
|
|
3355
|
+
actorAgentId: resolvedContext.agentId || null,
|
|
3356
|
+
conversationKey: context.conversationKey || null,
|
|
3357
|
+
localSessionKey: context.localSessionKey || null,
|
|
3358
|
+
localAgentId: resolveContextBoundLocalAgentId(resolvedContext),
|
|
3359
|
+
fetchImpl,
|
|
3360
|
+
});
|
|
3361
|
+
},
|
|
3306
3362
|
},
|
|
3307
3363
|
profile: {
|
|
3308
3364
|
getPublicIdentity: getRuntimePublicIdentity,
|
|
@@ -3565,6 +3621,47 @@ async function generateRuntimeProfileCard(context = {}) {
|
|
|
3565
3621
|
logger,
|
|
3566
3622
|
});
|
|
3567
3623
|
},
|
|
3624
|
+
inviteMember: async (context = {}) => {
|
|
3625
|
+
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
3626
|
+
return inviteModeratedWorldMember({
|
|
3627
|
+
cfg: resolvedContext.cfg || {},
|
|
3628
|
+
accountId: resolvedContext.accountId || null,
|
|
3629
|
+
runtimeConfig: resolvedContext.runtimeConfig || null,
|
|
3630
|
+
agentId: resolvedContext.agentId || null,
|
|
3631
|
+
worldId: context.worldId || null,
|
|
3632
|
+
targetAgentId: context.targetAgentId || null,
|
|
3633
|
+
identity: context.identity || null,
|
|
3634
|
+
inviteMessage: context.inviteMessage || null,
|
|
3635
|
+
fetchImpl,
|
|
3636
|
+
logger,
|
|
3637
|
+
});
|
|
3638
|
+
},
|
|
3639
|
+
revokeInvite: async (context = {}) => {
|
|
3640
|
+
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
3641
|
+
return revokeModeratedWorldInvite({
|
|
3642
|
+
cfg: resolvedContext.cfg || {},
|
|
3643
|
+
accountId: resolvedContext.accountId || null,
|
|
3644
|
+
runtimeConfig: resolvedContext.runtimeConfig || null,
|
|
3645
|
+
agentId: resolvedContext.agentId || null,
|
|
3646
|
+
worldId: context.worldId || null,
|
|
3647
|
+
targetAgentId: context.targetAgentId || null,
|
|
3648
|
+
fetchImpl,
|
|
3649
|
+
logger,
|
|
3650
|
+
});
|
|
3651
|
+
},
|
|
3652
|
+
listInvites: async (context = {}) => {
|
|
3653
|
+
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
3654
|
+
return fetchModeratedWorldInvites({
|
|
3655
|
+
cfg: resolvedContext.cfg || {},
|
|
3656
|
+
accountId: resolvedContext.accountId || null,
|
|
3657
|
+
runtimeConfig: resolvedContext.runtimeConfig || null,
|
|
3658
|
+
agentId: resolvedContext.agentId || null,
|
|
3659
|
+
worldId: context.worldId || null,
|
|
3660
|
+
status: context.status || 'invited',
|
|
3661
|
+
fetchImpl,
|
|
3662
|
+
logger,
|
|
3663
|
+
});
|
|
3664
|
+
},
|
|
3568
3665
|
},
|
|
3569
3666
|
membership: {
|
|
3570
3667
|
listWorldMembers: async (context = {}) => {
|
|
@@ -3939,6 +4036,47 @@ async function generateRuntimeProfileCard(context = {}) {
|
|
|
3939
4036
|
logger,
|
|
3940
4037
|
});
|
|
3941
4038
|
},
|
|
4039
|
+
inviteMember: async (context = {}) => {
|
|
4040
|
+
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
4041
|
+
return inviteModeratedWorldMember({
|
|
4042
|
+
cfg: resolvedContext.cfg || {},
|
|
4043
|
+
accountId: resolvedContext.accountId || null,
|
|
4044
|
+
runtimeConfig: resolvedContext.runtimeConfig || null,
|
|
4045
|
+
agentId: resolvedContext.agentId || null,
|
|
4046
|
+
worldId: context.worldId || null,
|
|
4047
|
+
targetAgentId: context.targetAgentId || null,
|
|
4048
|
+
identity: context.identity || null,
|
|
4049
|
+
inviteMessage: context.inviteMessage || null,
|
|
4050
|
+
fetchImpl,
|
|
4051
|
+
logger,
|
|
4052
|
+
});
|
|
4053
|
+
},
|
|
4054
|
+
revokeInvite: async (context = {}) => {
|
|
4055
|
+
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
4056
|
+
return revokeModeratedWorldInvite({
|
|
4057
|
+
cfg: resolvedContext.cfg || {},
|
|
4058
|
+
accountId: resolvedContext.accountId || null,
|
|
4059
|
+
runtimeConfig: resolvedContext.runtimeConfig || null,
|
|
4060
|
+
agentId: resolvedContext.agentId || null,
|
|
4061
|
+
worldId: context.worldId || null,
|
|
4062
|
+
targetAgentId: context.targetAgentId || null,
|
|
4063
|
+
fetchImpl,
|
|
4064
|
+
logger,
|
|
4065
|
+
});
|
|
4066
|
+
},
|
|
4067
|
+
listInvites: async (context = {}) => {
|
|
4068
|
+
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
4069
|
+
return fetchModeratedWorldInvites({
|
|
4070
|
+
cfg: resolvedContext.cfg || {},
|
|
4071
|
+
accountId: resolvedContext.accountId || null,
|
|
4072
|
+
runtimeConfig: resolvedContext.runtimeConfig || null,
|
|
4073
|
+
agentId: resolvedContext.agentId || null,
|
|
4074
|
+
worldId: context.worldId || null,
|
|
4075
|
+
status: context.status || 'invited',
|
|
4076
|
+
fetchImpl,
|
|
4077
|
+
logger,
|
|
4078
|
+
});
|
|
4079
|
+
},
|
|
3942
4080
|
},
|
|
3943
4081
|
membership: {
|
|
3944
4082
|
listWorldMembers: async (context = {}) => {
|
|
@@ -8,6 +8,12 @@ const REQUIRED_KEYS = ['enabled', 'serverUrl', 'apiKey', 'accountId'];
|
|
|
8
8
|
|
|
9
9
|
export const CLAWORLD_CHANNEL_ID = 'claworld';
|
|
10
10
|
|
|
11
|
+
export const claworldPluginConfigJsonSchema = {
|
|
12
|
+
type: 'object',
|
|
13
|
+
additionalProperties: false,
|
|
14
|
+
properties: {},
|
|
15
|
+
};
|
|
16
|
+
|
|
11
17
|
const AGENT_REGISTRATION_SCHEMA = {
|
|
12
18
|
type: 'object',
|
|
13
19
|
additionalProperties: false,
|
|
@@ -647,10 +647,7 @@ export function resolveClaworldManagedRuntimeOptions({
|
|
|
647
647
|
const name = normalizeText(overrides.name, normalizeText(existingBackup.name, displayName));
|
|
648
648
|
const existingRegistrationDisplayName = normalizeRegistrationDisplayName(
|
|
649
649
|
existingAccount?.registration?.displayName,
|
|
650
|
-
normalizeRegistrationDisplayName(
|
|
651
|
-
existingAccount?.localAgent?.displayName,
|
|
652
|
-
normalizeRegistrationDisplayName(existingBackup.registrationDisplayName, null),
|
|
653
|
-
),
|
|
650
|
+
normalizeRegistrationDisplayName(existingBackup.registrationDisplayName, null),
|
|
654
651
|
);
|
|
655
652
|
const registrationDisplayName = appToken && !explicitRegistrationDisplayName
|
|
656
653
|
? null
|
|
@@ -173,13 +173,16 @@ const TERMINAL_WORLD_ACTIONS = Object.freeze([
|
|
|
173
173
|
'list_world_activity',
|
|
174
174
|
'list_broadcast_history',
|
|
175
175
|
'manage_members',
|
|
176
|
+
'list_invites',
|
|
177
|
+
'invite_member',
|
|
178
|
+
'revoke_invite',
|
|
176
179
|
]);
|
|
177
180
|
|
|
178
181
|
const TERMINAL_CONVERSATION_ACTIONS = Object.freeze([
|
|
179
182
|
'request',
|
|
180
183
|
'accept',
|
|
181
184
|
'reject',
|
|
182
|
-
'
|
|
185
|
+
'close',
|
|
183
186
|
'get_state',
|
|
184
187
|
'list_related',
|
|
185
188
|
]);
|
|
@@ -235,6 +238,7 @@ function normalizeTerminalWorldAction(params = {}) {
|
|
|
235
238
|
requireManageWorldField('action', `action must be one of ${TERMINAL_WORLD_ACTIONS.join(', ')}`);
|
|
236
239
|
}
|
|
237
240
|
if (!normalizeText(params.worldId, null)) return 'list_owned_worlds';
|
|
241
|
+
if (normalizeText(params.targetAgentId, null) || normalizeText(params.identity, null)) return 'invite_member';
|
|
238
242
|
if (normalizeText(params.announcementText, null)) return 'publish_broadcast';
|
|
239
243
|
if (normalizeText(params.participantContextText, null)) return 'update_world_profile';
|
|
240
244
|
if (
|
|
@@ -711,6 +715,9 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
|
|
|
711
715
|
broadcastEnabled: booleanParam({ description: 'Whether a world subscription should receive broadcasts.' }),
|
|
712
716
|
broadcast: objectParam({ description: 'Optional broadcast config for update_world or set_world_broadcast_preference.', additionalProperties: true }),
|
|
713
717
|
subscriptionId: stringParam({ description: 'Existing subscription id for unsubscribe_world.', minLength: 1 }),
|
|
718
|
+
targetAgentId: stringParam({ description: 'Target agent id for private-world invitation actions.', minLength: 1 }),
|
|
719
|
+
identity: stringParam({ description: 'Target public identity displayName#code for private-world invitation actions.', minLength: 1 }),
|
|
720
|
+
inviteMessage: stringParam({ description: 'Optional private-world invitation note.', minLength: 1 }),
|
|
714
721
|
limit: integerParam({ description: 'Maximum rows for activity/member listing actions.', minimum: 1, maximum: 100 }),
|
|
715
722
|
status: stringParam({ description: 'Optional membership/subscription status filter.', minLength: 1 }),
|
|
716
723
|
},
|
|
@@ -796,6 +803,54 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
|
|
|
796
803
|
});
|
|
797
804
|
return buildTerminalActionResult({ tool: manageWorldsTool, action, payload });
|
|
798
805
|
}
|
|
806
|
+
if (action === 'list_invites') {
|
|
807
|
+
const worldId = normalizeText(params.worldId, null);
|
|
808
|
+
if (!worldId) requireManageWorldField('worldId');
|
|
809
|
+
const context = await resolveToolContext(api, plugin, params, {
|
|
810
|
+
requiredPublicIdentityCapability: 'list world invites',
|
|
811
|
+
});
|
|
812
|
+
const payload = await plugin.runtime.productShell.moderation.listInvites({
|
|
813
|
+
...context,
|
|
814
|
+
worldId,
|
|
815
|
+
status: params.status || 'invited',
|
|
816
|
+
});
|
|
817
|
+
return buildTerminalActionResult({ tool: manageWorldsTool, action, payload });
|
|
818
|
+
}
|
|
819
|
+
if (action === 'invite_member') {
|
|
820
|
+
const worldId = normalizeText(params.worldId, null);
|
|
821
|
+
if (!worldId) requireManageWorldField('worldId');
|
|
822
|
+
const targetAgentId = normalizeText(params.targetAgentId, null);
|
|
823
|
+
const identity = normalizeText(params.identity, null);
|
|
824
|
+
if (!targetAgentId && !identity) {
|
|
825
|
+
requireManageWorldField('targetAgentId', 'targetAgentId or identity is required for action=invite_member');
|
|
826
|
+
}
|
|
827
|
+
const context = await resolveToolContext(api, plugin, params, {
|
|
828
|
+
requiredPublicIdentityCapability: 'invite world member',
|
|
829
|
+
});
|
|
830
|
+
const payload = await plugin.runtime.productShell.moderation.inviteMember({
|
|
831
|
+
...context,
|
|
832
|
+
worldId,
|
|
833
|
+
targetAgentId,
|
|
834
|
+
identity,
|
|
835
|
+
inviteMessage: normalizeText(params.inviteMessage, null),
|
|
836
|
+
});
|
|
837
|
+
return buildTerminalActionResult({ tool: manageWorldsTool, action, payload });
|
|
838
|
+
}
|
|
839
|
+
if (action === 'revoke_invite') {
|
|
840
|
+
const worldId = normalizeText(params.worldId, null);
|
|
841
|
+
if (!worldId) requireManageWorldField('worldId');
|
|
842
|
+
const targetAgentId = normalizeText(params.targetAgentId, null);
|
|
843
|
+
if (!targetAgentId) requireManageWorldField('targetAgentId');
|
|
844
|
+
const context = await resolveToolContext(api, plugin, params, {
|
|
845
|
+
requiredPublicIdentityCapability: 'revoke world invite',
|
|
846
|
+
});
|
|
847
|
+
const payload = await plugin.runtime.productShell.moderation.revokeInvite({
|
|
848
|
+
...context,
|
|
849
|
+
worldId,
|
|
850
|
+
targetAgentId,
|
|
851
|
+
});
|
|
852
|
+
return buildTerminalActionResult({ tool: manageWorldsTool, action, payload });
|
|
853
|
+
}
|
|
799
854
|
if (
|
|
800
855
|
action === 'update_world'
|
|
801
856
|
&& typeof params.enabled === 'boolean'
|
|
@@ -850,7 +905,8 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
|
|
|
850
905
|
category: 'conversation_management',
|
|
851
906
|
usageNotes: [
|
|
852
907
|
'action=request starts a direct or world-scoped chat request.',
|
|
853
|
-
'action=list_related/get_state, accept, reject, and
|
|
908
|
+
'action=list_related/get_state, accept, reject, and close manage product-level conversation state decisions.',
|
|
909
|
+
'action=close is a backend close; natural peer-facing endings still use [[request_conversation_end]] inside the Conversation Session.',
|
|
854
910
|
'Do not use this tool for live conversation turns.',
|
|
855
911
|
],
|
|
856
912
|
}),
|
|
@@ -870,9 +926,8 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
|
|
|
870
926
|
worldId: worldIdProperty,
|
|
871
927
|
filters: objectParam({ description: 'List filters.', additionalProperties: true }),
|
|
872
928
|
chatRequestId: stringParam({ description: 'Request id for accept/reject.', minLength: 1 }),
|
|
873
|
-
conversationKey: stringParam({ description: 'Conversation key for get_state/
|
|
874
|
-
localSessionKey: stringParam({ description: 'Local conversation session key for get_state/
|
|
875
|
-
endingMessage: stringParam({ description: 'Optional final peer-facing message to pair with the conversation-end control token.', minLength: 1 }),
|
|
929
|
+
conversationKey: stringParam({ description: 'Conversation key for get_state/close.', minLength: 1 }),
|
|
930
|
+
localSessionKey: stringParam({ description: 'Local conversation session key for get_state/close.', minLength: 1 }),
|
|
876
931
|
},
|
|
877
932
|
}),
|
|
878
933
|
async execute(toolCallId, params = {}) {
|
|
@@ -891,41 +946,22 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
|
|
|
891
946
|
});
|
|
892
947
|
return rewriteToolResultName(result, manageConversationsTool, action);
|
|
893
948
|
}
|
|
894
|
-
if (action === '
|
|
949
|
+
if (action === 'close') {
|
|
895
950
|
const conversationKey = normalizeText(params.conversationKey, null);
|
|
896
951
|
const localSessionKey = normalizeText(params.localSessionKey, null);
|
|
897
952
|
if (!conversationKey && !localSessionKey) {
|
|
898
|
-
requireManageWorldField('conversationKey', 'conversationKey or localSessionKey is required for action=
|
|
953
|
+
requireManageWorldField('conversationKey', 'conversationKey or localSessionKey is required for action=close');
|
|
899
954
|
}
|
|
900
|
-
const
|
|
901
|
-
|
|
902
|
-
...
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
const result = await requireTerminalTool(internalTools, 'claworld_chat_inbox').execute(toolCallId, {
|
|
906
|
-
...params,
|
|
907
|
-
action: 'list',
|
|
908
|
-
filters,
|
|
955
|
+
const context = await resolveToolContext(api, plugin, params);
|
|
956
|
+
const payload = await plugin.helpers.social.closeConversation({
|
|
957
|
+
...context,
|
|
958
|
+
conversationKey,
|
|
959
|
+
localSessionKey,
|
|
909
960
|
});
|
|
910
|
-
const parsed = JSON.parse(result.content?.[0]?.text || '{}');
|
|
911
961
|
return buildTerminalActionResult({
|
|
912
962
|
tool: manageConversationsTool,
|
|
913
963
|
action,
|
|
914
|
-
payload
|
|
915
|
-
...parsed,
|
|
916
|
-
status: 'conversation_session_required',
|
|
917
|
-
ending: {
|
|
918
|
-
status: 'conversation_session_required',
|
|
919
|
-
controlToken: '[[request_conversation_end]]',
|
|
920
|
-
conversationKey,
|
|
921
|
-
localSessionKey,
|
|
922
|
-
endingMessage: normalizeText(params.endingMessage, null),
|
|
923
|
-
instruction:
|
|
924
|
-
'Send one final peer-facing reply from the Conversation Session and include [[request_conversation_end]] to request a formal close.',
|
|
925
|
-
},
|
|
926
|
-
requiresUserDecision: false,
|
|
927
|
-
nextAction: 'send_final_conversation_session_reply_with_request_conversation_end',
|
|
928
|
-
},
|
|
964
|
+
payload,
|
|
929
965
|
});
|
|
930
966
|
}
|
|
931
967
|
requireManageWorldField('action', `action must be one of ${TERMINAL_CONVERSATION_ACTIONS.join(', ')}`);
|
|
@@ -1074,7 +1110,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
1074
1110
|
'This is the only public join entrypoint for the default flow.',
|
|
1075
1111
|
'Provide one participantContextText that describes who the agent is in this world.',
|
|
1076
1112
|
'Expected behavior: on success it creates or updates the caller\'s active membership for that world and returns member-search, activity, subscription, and optional request-chat follow-up actions.',
|
|
1077
|
-
'When
|
|
1113
|
+
'When membershipStatus is active, use memberSearchAction or worldActivityAction before requestChatAction unless a target member is already known.',
|
|
1078
1114
|
'If the agent later needs fresh member results for the same world, call claworld_search(scope=world_members).',
|
|
1079
1115
|
],
|
|
1080
1116
|
examples: [
|
|
@@ -1336,6 +1336,22 @@ export class ClaworldRelayClient extends EventEmitter {
|
|
|
1336
1336
|
});
|
|
1337
1337
|
}
|
|
1338
1338
|
|
|
1339
|
+
async closeConversation({ actorAgentId, conversationKey = null, localSessionKey = null } = {}) {
|
|
1340
|
+
return await this.requestJson('/v1/chat-requests/conversations/close', {
|
|
1341
|
+
method: 'POST',
|
|
1342
|
+
headers: buildRuntimeAuthHeaders(this.runtimeConfig, { 'content-type': 'application/json' }),
|
|
1343
|
+
body: JSON.stringify({
|
|
1344
|
+
actorAgentId,
|
|
1345
|
+
...(conversationKey ? { conversationKey } : {}),
|
|
1346
|
+
...(localSessionKey ? { localSessionKey } : {}),
|
|
1347
|
+
}),
|
|
1348
|
+
}, {
|
|
1349
|
+
code: 'relay_conversation_close_failed',
|
|
1350
|
+
message: 'failed to close relay conversation',
|
|
1351
|
+
publicMessage: 'failed to close relay conversation',
|
|
1352
|
+
});
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1339
1355
|
async deliverMessage({ fromAgentId, targetAgentId, clientMessageId = null, payload = {}, conversation = {} } = {}) {
|
|
1340
1356
|
const resolvedClientMessageId = requireClientMessageId(clientMessageId);
|
|
1341
1357
|
const result = await this.requestJson('/v1/orchestration/messages', {
|
|
@@ -268,8 +268,9 @@ export function normalizeWorldJoinResponse(payload = {}, { worldId = null, agent
|
|
|
268
268
|
const normalizedWorldId = normalizeText(payload.worldId, worldId || 'unknown-world');
|
|
269
269
|
const normalizedAgentId = normalizeText(payload.agentId || membership?.agentId, agentId || null);
|
|
270
270
|
const membershipStatus = normalizeText(payload.membershipStatus || membership?.status, 'unknown');
|
|
271
|
+
const responseStatus = normalizeText(payload.status, membershipStatus === 'active' ? 'active' : 'accepted');
|
|
271
272
|
return {
|
|
272
|
-
status:
|
|
273
|
+
status: responseStatus,
|
|
273
274
|
worldId: normalizedWorldId,
|
|
274
275
|
agentId: normalizedAgentId,
|
|
275
276
|
worldRole: normalizeWorldRole(payload.worldRole, null),
|
|
@@ -339,7 +339,7 @@ export function projectToolJoinWorldResponse(
|
|
|
339
339
|
{ accountId = null } = {},
|
|
340
340
|
) {
|
|
341
341
|
return {
|
|
342
|
-
status: joinResult.membershipStatus === 'active' ? '
|
|
342
|
+
status: joinResult.membershipStatus === 'active' ? 'active' : 'accepted',
|
|
343
343
|
worldId: normalizeText(joinResult.worldId, null),
|
|
344
344
|
accountId: normalizeText(accountId, null),
|
|
345
345
|
worldRole: projectWorldRole(joinResult.worldRole, null),
|
|
@@ -92,6 +92,34 @@ function normalizeWorldBroadcastConfig(broadcast = null) {
|
|
|
92
92
|
};
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
function normalizeWorldInvite(payload = {}) {
|
|
96
|
+
return {
|
|
97
|
+
status: normalizeText(payload.status, null),
|
|
98
|
+
worldId: normalizeText(payload.worldId, null),
|
|
99
|
+
displayName: normalizeText(payload.displayName, null),
|
|
100
|
+
targetAgentId: normalizeText(payload.targetAgentId, null),
|
|
101
|
+
targetIdentity: normalizeText(payload.targetIdentity, null),
|
|
102
|
+
invitedByAgentId: normalizeText(payload.invitedByAgentId, null),
|
|
103
|
+
membershipId: normalizeText(payload.membershipId, null),
|
|
104
|
+
membershipStatus: normalizeText(payload.membershipStatus, null),
|
|
105
|
+
created: normalizeOptionalBoolean(payload.created, null),
|
|
106
|
+
invitedAt: normalizeText(payload.invitedAt, null),
|
|
107
|
+
inviteMessage: normalizeText(payload.inviteMessage, null),
|
|
108
|
+
inviteRevokedAt: normalizeText(payload.inviteRevokedAt, null),
|
|
109
|
+
notificationId: normalizeText(payload.notificationId, null),
|
|
110
|
+
nextAction: normalizeText(payload.nextAction, null),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function normalizeWorldInviteList(payload = {}) {
|
|
115
|
+
return {
|
|
116
|
+
worldId: normalizeText(payload.worldId, null),
|
|
117
|
+
items: Array.isArray(payload.items) ? payload.items.map((item) => normalizeWorldInvite(item)) : [],
|
|
118
|
+
totalItems: normalizeOptionalInteger(payload.totalItems, 0),
|
|
119
|
+
nextAction: normalizeText(payload.nextAction, null),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
95
123
|
function normalizeManagedWorld(payload = {}) {
|
|
96
124
|
return {
|
|
97
125
|
worldId: normalizeText(payload.worldId, null),
|
|
@@ -465,6 +493,170 @@ export async function manageModeratedWorld({
|
|
|
465
493
|
return normalizeManagedWorld(result.body);
|
|
466
494
|
}
|
|
467
495
|
|
|
496
|
+
export async function inviteModeratedWorldMember({
|
|
497
|
+
cfg = {},
|
|
498
|
+
accountId = null,
|
|
499
|
+
runtimeConfig = null,
|
|
500
|
+
agentId = null,
|
|
501
|
+
worldId = null,
|
|
502
|
+
targetAgentId = null,
|
|
503
|
+
identity = null,
|
|
504
|
+
inviteMessage = null,
|
|
505
|
+
fetchImpl,
|
|
506
|
+
logger = console,
|
|
507
|
+
} = {}) {
|
|
508
|
+
if (typeof fetchImpl !== 'function') {
|
|
509
|
+
throw new Error('fetch is unavailable for claworld world invite helper');
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
const resolvedAgentId = normalizeText(agentId, null);
|
|
513
|
+
if (!resolvedAgentId) {
|
|
514
|
+
throw new Error('claworld world invite helper requires agentId');
|
|
515
|
+
}
|
|
516
|
+
const resolvedWorldId = normalizeText(worldId, null);
|
|
517
|
+
if (!resolvedWorldId) {
|
|
518
|
+
throw new Error('claworld world invite helper requires worldId');
|
|
519
|
+
}
|
|
520
|
+
const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
|
|
521
|
+
const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
|
|
522
|
+
const result = await fetchJson(fetchImpl, `${baseUrl}/v1/moderation/worlds/${encodeURIComponent(resolvedWorldId)}/invitations`, {
|
|
523
|
+
method: 'POST',
|
|
524
|
+
headers: buildRuntimeAuthHeaders(resolvedRuntimeConfig, {
|
|
525
|
+
accept: 'application/json',
|
|
526
|
+
'content-type': 'application/json',
|
|
527
|
+
...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
|
|
528
|
+
}),
|
|
529
|
+
body: JSON.stringify({
|
|
530
|
+
agentId: resolvedAgentId,
|
|
531
|
+
...(normalizeText(targetAgentId, null) ? { targetAgentId: normalizeText(targetAgentId, null) } : {}),
|
|
532
|
+
...(normalizeText(identity, null) ? { identity: normalizeText(identity, null) } : {}),
|
|
533
|
+
...(normalizeText(inviteMessage, null) ? { inviteMessage: normalizeText(inviteMessage, null) } : {}),
|
|
534
|
+
}),
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
if (!result.ok) {
|
|
538
|
+
logger.error?.('[claworld:moderation] world invite failed', {
|
|
539
|
+
status: result.status,
|
|
540
|
+
worldId: resolvedWorldId,
|
|
541
|
+
accountId: resolvedRuntimeConfig.accountId || accountId || null,
|
|
542
|
+
body: result.body,
|
|
543
|
+
});
|
|
544
|
+
throw createModerationHttpError('invite_member', result, {
|
|
545
|
+
accountId: resolvedRuntimeConfig.accountId || accountId || null,
|
|
546
|
+
worldId: resolvedWorldId,
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
return normalizeWorldInvite(result.body);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
export async function revokeModeratedWorldInvite({
|
|
554
|
+
cfg = {},
|
|
555
|
+
accountId = null,
|
|
556
|
+
runtimeConfig = null,
|
|
557
|
+
agentId = null,
|
|
558
|
+
worldId = null,
|
|
559
|
+
targetAgentId = null,
|
|
560
|
+
fetchImpl,
|
|
561
|
+
logger = console,
|
|
562
|
+
} = {}) {
|
|
563
|
+
if (typeof fetchImpl !== 'function') {
|
|
564
|
+
throw new Error('fetch is unavailable for claworld world invite revoke helper');
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
const resolvedAgentId = normalizeText(agentId, null);
|
|
568
|
+
if (!resolvedAgentId) {
|
|
569
|
+
throw new Error('claworld world invite revoke helper requires agentId');
|
|
570
|
+
}
|
|
571
|
+
const resolvedWorldId = normalizeText(worldId, null);
|
|
572
|
+
if (!resolvedWorldId) {
|
|
573
|
+
throw new Error('claworld world invite revoke helper requires worldId');
|
|
574
|
+
}
|
|
575
|
+
const resolvedTargetAgentId = normalizeText(targetAgentId, null);
|
|
576
|
+
if (!resolvedTargetAgentId) {
|
|
577
|
+
throw new Error('claworld world invite revoke helper requires targetAgentId');
|
|
578
|
+
}
|
|
579
|
+
const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
|
|
580
|
+
const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
|
|
581
|
+
const result = await fetchJson(fetchImpl, `${baseUrl}/v1/moderation/worlds/${encodeURIComponent(resolvedWorldId)}/invitations/revoke`, {
|
|
582
|
+
method: 'POST',
|
|
583
|
+
headers: buildRuntimeAuthHeaders(resolvedRuntimeConfig, {
|
|
584
|
+
accept: 'application/json',
|
|
585
|
+
'content-type': 'application/json',
|
|
586
|
+
...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
|
|
587
|
+
}),
|
|
588
|
+
body: JSON.stringify({
|
|
589
|
+
agentId: resolvedAgentId,
|
|
590
|
+
targetAgentId: resolvedTargetAgentId,
|
|
591
|
+
}),
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
if (!result.ok) {
|
|
595
|
+
logger.error?.('[claworld:moderation] world invite revoke failed', {
|
|
596
|
+
status: result.status,
|
|
597
|
+
worldId: resolvedWorldId,
|
|
598
|
+
accountId: resolvedRuntimeConfig.accountId || accountId || null,
|
|
599
|
+
body: result.body,
|
|
600
|
+
});
|
|
601
|
+
throw createModerationHttpError('revoke_invite', result, {
|
|
602
|
+
accountId: resolvedRuntimeConfig.accountId || accountId || null,
|
|
603
|
+
worldId: resolvedWorldId,
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
return normalizeWorldInvite(result.body);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
export async function fetchModeratedWorldInvites({
|
|
611
|
+
cfg = {},
|
|
612
|
+
accountId = null,
|
|
613
|
+
runtimeConfig = null,
|
|
614
|
+
agentId = null,
|
|
615
|
+
worldId = null,
|
|
616
|
+
status = 'invited',
|
|
617
|
+
fetchImpl,
|
|
618
|
+
logger = console,
|
|
619
|
+
} = {}) {
|
|
620
|
+
if (typeof fetchImpl !== 'function') {
|
|
621
|
+
throw new Error('fetch is unavailable for claworld world invites helper');
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
const resolvedAgentId = normalizeText(agentId, null);
|
|
625
|
+
if (!resolvedAgentId) {
|
|
626
|
+
throw new Error('claworld world invites helper requires agentId');
|
|
627
|
+
}
|
|
628
|
+
const resolvedWorldId = normalizeText(worldId, null);
|
|
629
|
+
if (!resolvedWorldId) {
|
|
630
|
+
throw new Error('claworld world invites helper requires worldId');
|
|
631
|
+
}
|
|
632
|
+
const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
|
|
633
|
+
const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
|
|
634
|
+
const requestUrl = new URL(`${baseUrl}/v1/moderation/worlds/${encodeURIComponent(resolvedWorldId)}/invitations`);
|
|
635
|
+
requestUrl.searchParams.set('agentId', resolvedAgentId);
|
|
636
|
+
if (normalizeText(status, null)) requestUrl.searchParams.set('status', normalizeText(status, null));
|
|
637
|
+
const result = await fetchJson(fetchImpl, requestUrl.toString(), {
|
|
638
|
+
headers: buildRuntimeAuthHeaders(resolvedRuntimeConfig, {
|
|
639
|
+
accept: 'application/json',
|
|
640
|
+
...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
|
|
641
|
+
}),
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
if (!result.ok) {
|
|
645
|
+
logger.error?.('[claworld:moderation] world invites fetch failed', {
|
|
646
|
+
status: result.status,
|
|
647
|
+
worldId: resolvedWorldId,
|
|
648
|
+
accountId: resolvedRuntimeConfig.accountId || accountId || null,
|
|
649
|
+
body: result.body,
|
|
650
|
+
});
|
|
651
|
+
throw createModerationHttpError('list_invites', result, {
|
|
652
|
+
accountId: resolvedRuntimeConfig.accountId || accountId || null,
|
|
653
|
+
worldId: resolvedWorldId,
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
return normalizeWorldInviteList(result.body);
|
|
658
|
+
}
|
|
659
|
+
|
|
468
660
|
export async function broadcastModeratedWorld({
|
|
469
661
|
cfg = {},
|
|
470
662
|
accountId = null,
|