@xfxstudio/claworld 2026.4.22-testing.5 → 2026.4.22-testing.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/index.js +14 -0
- package/openclaw.plugin.json +7 -7
- package/package.json +1 -1
- package/skills/claworld-a2a-channel-agent/SKILL.md +22 -6
- package/skills/claworld-help/SKILL.md +38 -232
- package/skills/claworld-join-and-chat/SKILL.md +63 -496
- package/skills/claworld-manage-worlds/SKILL.md +50 -252
- package/src/lib/relay/agent-readable-markdown.js +4 -2
- package/src/lib/relay/kickoff-progress.js +8 -0
- package/src/openclaw/index.js +25 -0
- package/src/openclaw/plugin/claworld-channel-plugin.js +496 -2
- package/src/openclaw/plugin/config-schema.js +3 -3
- package/src/openclaw/plugin/onboarding.js +1 -1
- package/src/openclaw/plugin/register-tooling.js +2 -2
- package/src/openclaw/plugin/register.js +865 -99
- package/src/openclaw/plugin/relay-client.js +16 -0
- package/src/openclaw/runtime/demo-session-bootstrap.js +48 -0
- package/src/openclaw/runtime/inbound-session-router.js +20 -4
- package/src/openclaw/runtime/outbound-session-bridge.js +60 -0
- package/src/openclaw/runtime/product-shell-helper.js +125 -24
- package/src/openclaw/runtime/session-routing.js +144 -0
- package/src/openclaw/runtime/tool-contracts.js +72 -20
- package/src/openclaw/runtime/tool-inventory.js +29 -25
- package/src/openclaw/runtime/working-memory.js +1086 -0
- package/src/openclaw/runtime/workspace-resolver.js +109 -0
- package/src/openclaw/runtime/world-moderation-helper.js +11 -1
- package/src/product-shell/contracts/world-orchestration.js +7 -4
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { createClaworldChannelPlugin } from './claworld-channel-plugin.js';
|
|
2
2
|
import {
|
|
3
3
|
projectToolChatRequestMutationResponse,
|
|
4
|
-
projectToolCandidateFeedResponse,
|
|
5
4
|
projectToolCreateWorldResponse,
|
|
6
5
|
projectToolFeedbackSubmissionResponse,
|
|
7
6
|
projectToolJoinWorldResponse,
|
|
@@ -11,6 +10,16 @@ import {
|
|
|
11
10
|
projectToolWorldSearchResponse,
|
|
12
11
|
} from '../runtime/tool-contracts.js';
|
|
13
12
|
import { CLAWORLD_TOOL_CONTRACT_VERSION } from '../runtime/tool-inventory.js';
|
|
13
|
+
import {
|
|
14
|
+
CLAWORLD_BOOTSTRAP_TARGETS,
|
|
15
|
+
appendClaworldJournalEvent,
|
|
16
|
+
buildClaworldBootstrapPromptContext,
|
|
17
|
+
buildClaworldContextPointer,
|
|
18
|
+
buildClaworldToolMaintenanceEvent,
|
|
19
|
+
ensureClaworldWorkingMemory,
|
|
20
|
+
resolveClaworldBootstrapTarget,
|
|
21
|
+
} from '../runtime/working-memory.js';
|
|
22
|
+
import { resolveOpenClawWorkspaceRoot } from '../runtime/workspace-resolver.js';
|
|
14
23
|
import { setClaworldRuntime } from './runtime.js';
|
|
15
24
|
import {
|
|
16
25
|
CHAT_REQUEST_APPROVAL_POLICY_MODES,
|
|
@@ -72,6 +81,48 @@ function buildClaworldStatusRoute(plugin) {
|
|
|
72
81
|
};
|
|
73
82
|
}
|
|
74
83
|
|
|
84
|
+
async function resolveHookWorkspaceRoot(api, event = {}, ctx = {}) {
|
|
85
|
+
const directWorkspaceRoot = resolveOpenClawWorkspaceRoot({ sources: [event, ctx] });
|
|
86
|
+
if (directWorkspaceRoot) return directWorkspaceRoot;
|
|
87
|
+
const cfg = await loadCurrentConfig(api);
|
|
88
|
+
return resolveOpenClawWorkspaceRoot({
|
|
89
|
+
sources: [event, ctx],
|
|
90
|
+
config: cfg,
|
|
91
|
+
agentId: ctx?.agentId ?? event?.agentId,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function getHookLogger(api) {
|
|
96
|
+
return api?.logger || api?.runtime?.logger || console;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function parseHookToolPayload(result) {
|
|
100
|
+
if (!result || typeof result !== 'object') return null;
|
|
101
|
+
const text = Array.isArray(result.content)
|
|
102
|
+
? result.content.find((entry) => entry?.type === 'text' && typeof entry.text === 'string')?.text
|
|
103
|
+
: null;
|
|
104
|
+
if (!text) return null;
|
|
105
|
+
try {
|
|
106
|
+
const parsed = JSON.parse(text);
|
|
107
|
+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : null;
|
|
108
|
+
} catch {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function isSuccessfulHookToolCall(event = {}) {
|
|
114
|
+
if (event?.error || event?.isError === true) return false;
|
|
115
|
+
const result = event?.result ?? event?.output ?? event?.response ?? null;
|
|
116
|
+
if (result?.isError === true) return false;
|
|
117
|
+
const payload = parseHookToolPayload(result);
|
|
118
|
+
if (normalizeText(payload?.status, null) === 'error') return false;
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function hookToolResult(event = {}) {
|
|
123
|
+
return event?.result ?? event?.output ?? event?.response ?? null;
|
|
124
|
+
}
|
|
125
|
+
|
|
75
126
|
const CHAT_INBOX_FILTER_DIRECTIONS = Object.freeze([
|
|
76
127
|
'inbound',
|
|
77
128
|
'outbound',
|
|
@@ -92,6 +143,134 @@ const CHAT_INBOX_FILTER_STATUSES = Object.freeze([
|
|
|
92
143
|
'ended',
|
|
93
144
|
]);
|
|
94
145
|
|
|
146
|
+
const TERMINAL_ACCOUNT_ACTIONS = Object.freeze([
|
|
147
|
+
'view_account',
|
|
148
|
+
'activate_account',
|
|
149
|
+
'update_display_name',
|
|
150
|
+
'update_human_profile',
|
|
151
|
+
'update_agent_profile',
|
|
152
|
+
'set_discoverability',
|
|
153
|
+
'set_contactability',
|
|
154
|
+
'set_chat_policy',
|
|
155
|
+
'set_proactivity',
|
|
156
|
+
'subscribe_person',
|
|
157
|
+
'unsubscribe_person',
|
|
158
|
+
]);
|
|
159
|
+
|
|
160
|
+
const TERMINAL_WORLD_ACTIONS = Object.freeze([
|
|
161
|
+
'list_owned_worlds',
|
|
162
|
+
'list_joined_worlds',
|
|
163
|
+
'get_world',
|
|
164
|
+
'create_world',
|
|
165
|
+
'update_world',
|
|
166
|
+
'join_world',
|
|
167
|
+
'update_world_profile',
|
|
168
|
+
'leave_world',
|
|
169
|
+
'subscribe_world',
|
|
170
|
+
'unsubscribe_world',
|
|
171
|
+
'set_world_broadcast_preference',
|
|
172
|
+
'publish_broadcast',
|
|
173
|
+
'list_world_activity',
|
|
174
|
+
'list_broadcast_history',
|
|
175
|
+
'manage_members',
|
|
176
|
+
]);
|
|
177
|
+
|
|
178
|
+
const TERMINAL_CONVERSATION_ACTIONS = Object.freeze([
|
|
179
|
+
'request',
|
|
180
|
+
'accept',
|
|
181
|
+
'reject',
|
|
182
|
+
'end',
|
|
183
|
+
'get_state',
|
|
184
|
+
'list_related',
|
|
185
|
+
]);
|
|
186
|
+
|
|
187
|
+
const ACCOUNT_IMPLEMENTATION_ACTIONS = Object.freeze({
|
|
188
|
+
view_account: 'view',
|
|
189
|
+
activate_account: 'update_identity',
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
const WORLD_IMPLEMENTATION_ACTIONS = Object.freeze({
|
|
193
|
+
list_owned_worlds: 'list',
|
|
194
|
+
list_joined_worlds: 'list_memberships',
|
|
195
|
+
update_world: 'update_context',
|
|
196
|
+
update_world_profile: 'update_profile',
|
|
197
|
+
publish_broadcast: 'broadcast',
|
|
198
|
+
leave_world: 'leave',
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
function normalizeTerminalAction(action, allowedActions, fallback = null) {
|
|
202
|
+
const normalized = normalizeText(action, fallback);
|
|
203
|
+
return allowedActions.includes(normalized) ? normalized : fallback;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function hasExplicitAction(params = {}) {
|
|
207
|
+
return Object.prototype.hasOwnProperty.call(params, 'action') && normalizeText(params.action, null) != null;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function normalizeTerminalAccountAction(params = {}) {
|
|
211
|
+
if (hasExplicitAction(params)) {
|
|
212
|
+
const explicitAction = normalizeText(params.action, null);
|
|
213
|
+
const terminalAction = normalizeTerminalAction(explicitAction, TERMINAL_ACCOUNT_ACTIONS, null);
|
|
214
|
+
if (terminalAction) return terminalAction;
|
|
215
|
+
requireManageWorldField('action', `action must be one of ${TERMINAL_ACCOUNT_ACTIONS.join(', ')}`);
|
|
216
|
+
}
|
|
217
|
+
if (normalizeText(params.displayName, null)) return 'update_display_name';
|
|
218
|
+
if (Object.prototype.hasOwnProperty.call(params, 'humanProfile')) return 'update_human_profile';
|
|
219
|
+
if (
|
|
220
|
+
Object.prototype.hasOwnProperty.call(params, 'agentProfile')
|
|
221
|
+
|| Object.prototype.hasOwnProperty.call(params, 'profile')
|
|
222
|
+
) return 'update_agent_profile';
|
|
223
|
+
if (Object.prototype.hasOwnProperty.call(params, 'discoverable')) return 'set_discoverability';
|
|
224
|
+
if (Object.prototype.hasOwnProperty.call(params, 'contactable')) return 'set_contactability';
|
|
225
|
+
if (normalizeObject(params.chatRequestApprovalPolicy, null)) return 'set_chat_policy';
|
|
226
|
+
if (Object.prototype.hasOwnProperty.call(params, 'proactivitySettings')) return 'set_proactivity';
|
|
227
|
+
return 'view_account';
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function normalizeTerminalWorldAction(params = {}) {
|
|
231
|
+
if (hasExplicitAction(params)) {
|
|
232
|
+
const explicitAction = normalizeText(params.action, null);
|
|
233
|
+
const terminalAction = normalizeTerminalAction(explicitAction, TERMINAL_WORLD_ACTIONS, null);
|
|
234
|
+
if (terminalAction) return terminalAction;
|
|
235
|
+
requireManageWorldField('action', `action must be one of ${TERMINAL_WORLD_ACTIONS.join(', ')}`);
|
|
236
|
+
}
|
|
237
|
+
if (!normalizeText(params.worldId, null)) return 'list_owned_worlds';
|
|
238
|
+
if (normalizeText(params.announcementText, null)) return 'publish_broadcast';
|
|
239
|
+
if (normalizeText(params.participantContextText, null)) return 'update_world_profile';
|
|
240
|
+
if (
|
|
241
|
+
normalizeText(params.worldContextText, null)
|
|
242
|
+
|| normalizeText(params.displayName, null)
|
|
243
|
+
|| normalizeObject(params.broadcast, null)
|
|
244
|
+
|| typeof params.enabled === 'boolean'
|
|
245
|
+
) {
|
|
246
|
+
return 'update_world';
|
|
247
|
+
}
|
|
248
|
+
return 'get_world';
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function normalizeTerminalConversationAction(action, fallback = 'list_related', { throwOnInvalid = false } = {}) {
|
|
252
|
+
const normalized = normalizeText(action, null);
|
|
253
|
+
if (!normalized) return fallback;
|
|
254
|
+
if (TERMINAL_CONVERSATION_ACTIONS.includes(normalized)) return normalized;
|
|
255
|
+
if (throwOnInvalid) {
|
|
256
|
+
requireManageWorldField('action', `action must be one of ${TERMINAL_CONVERSATION_ACTIONS.join(', ')}`);
|
|
257
|
+
}
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function buildTerminalActionResult({ tool, action, payload = {}, status = null } = {}) {
|
|
262
|
+
const normalizedPayload = payload && typeof payload === 'object' && !Array.isArray(payload)
|
|
263
|
+
? payload
|
|
264
|
+
: { value: payload };
|
|
265
|
+
const normalizedStatus = status || normalizeText(normalizedPayload.status, 'ok');
|
|
266
|
+
return buildToolResult({
|
|
267
|
+
...normalizedPayload,
|
|
268
|
+
tool,
|
|
269
|
+
action,
|
|
270
|
+
status: normalizedStatus,
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
95
274
|
function normalizeChatInboxListFiltersInput(params = {}) {
|
|
96
275
|
const source = normalizeObject(params.filters, {}) || {};
|
|
97
276
|
const normalized = {
|
|
@@ -109,6 +288,577 @@ function normalizeChatInboxListFiltersInput(params = {}) {
|
|
|
109
288
|
);
|
|
110
289
|
}
|
|
111
290
|
|
|
291
|
+
function parseToolResultPayload(result = null) {
|
|
292
|
+
const text = result?.content?.[0]?.text;
|
|
293
|
+
if (typeof text !== 'string') return null;
|
|
294
|
+
try {
|
|
295
|
+
return JSON.parse(text);
|
|
296
|
+
} catch {
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function rewriteToolResultName(result, toolName, action = null) {
|
|
302
|
+
const payload = parseToolResultPayload(result);
|
|
303
|
+
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) return result;
|
|
304
|
+
return buildToolResult({
|
|
305
|
+
...payload,
|
|
306
|
+
tool: toolName,
|
|
307
|
+
...(action ? { action } : {}),
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function requireTerminalTool(internalTools, toolName) {
|
|
312
|
+
const tool = internalTools.get(toolName);
|
|
313
|
+
if (!tool || typeof tool.execute !== 'function') {
|
|
314
|
+
throw new Error(`terminal public tool adapter requires ${toolName}`);
|
|
315
|
+
}
|
|
316
|
+
return tool;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function createTerminalToolAdapters(api, plugin, internalTools) {
|
|
320
|
+
const accountIdProperty = stringParam({
|
|
321
|
+
description: 'Claworld account id to execute the tool against.',
|
|
322
|
+
minLength: 1,
|
|
323
|
+
examples: ['claworld'],
|
|
324
|
+
});
|
|
325
|
+
const worldIdProperty = stringParam({
|
|
326
|
+
description: 'Canonical world id.',
|
|
327
|
+
minLength: 1,
|
|
328
|
+
examples: ['dating-demo-world'],
|
|
329
|
+
});
|
|
330
|
+
const searchTool = 'claworld_search';
|
|
331
|
+
const manageWorldsTool = 'claworld_manage_worlds';
|
|
332
|
+
const manageConversationsTool = 'claworld_manage_conversations';
|
|
333
|
+
const accountTool = 'claworld_manage_account';
|
|
334
|
+
const publicProfileTool = 'claworld_get_public_profile';
|
|
335
|
+
|
|
336
|
+
return [
|
|
337
|
+
{
|
|
338
|
+
name: accountTool,
|
|
339
|
+
label: 'Claworld Manage Account',
|
|
340
|
+
description: 'Terminal account surface for readiness, public identity, global profile, share-card generation, and account-level chat policy.',
|
|
341
|
+
metadata: buildToolMetadata({
|
|
342
|
+
category: 'account',
|
|
343
|
+
usageNotes: [
|
|
344
|
+
'Use this owner-facing account surface for activation, profile, policy, and subscription decisions.',
|
|
345
|
+
'Use action=view_account for readiness; update_display_name, update_agent_profile, or set_chat_policy for common account mutations.',
|
|
346
|
+
'Use subscribe_person or unsubscribe_person when a search/profile result exposes a person subscription target.',
|
|
347
|
+
],
|
|
348
|
+
}),
|
|
349
|
+
parameters: objectParam({
|
|
350
|
+
description: 'Terminal account management payload.',
|
|
351
|
+
required: ['accountId'],
|
|
352
|
+
properties: {
|
|
353
|
+
accountId: accountIdProperty,
|
|
354
|
+
action: stringParam({
|
|
355
|
+
description: 'Account action.',
|
|
356
|
+
enumValues: TERMINAL_ACCOUNT_ACTIONS,
|
|
357
|
+
examples: ['view_account', 'update_display_name', 'set_chat_policy'],
|
|
358
|
+
}),
|
|
359
|
+
displayName: stringParam({
|
|
360
|
+
description: 'Public-facing display name for activate_account or update_display_name.',
|
|
361
|
+
minLength: 1,
|
|
362
|
+
examples: ['Moza', '小发发'],
|
|
363
|
+
}),
|
|
364
|
+
profile: stringParam({
|
|
365
|
+
description: 'Optional global profile text used when updating the agent profile.',
|
|
366
|
+
examples: ['喜欢慢节奏介绍,也愿意先让 agent 做初步认识。🙂'],
|
|
367
|
+
}),
|
|
368
|
+
humanProfile: stringParam({
|
|
369
|
+
description: 'Owner-facing human profile text for update_human_profile.',
|
|
370
|
+
examples: ['周末在上海,喜欢网球和安静咖啡馆。'],
|
|
371
|
+
}),
|
|
372
|
+
agentProfile: stringParam({
|
|
373
|
+
description: 'Agent-facing profile/personality text for update_agent_profile.',
|
|
374
|
+
examples: ['偏主动但会先确认边界,擅长总结和约局。'],
|
|
375
|
+
}),
|
|
376
|
+
discoverable: booleanParam({ description: 'Whether this account can appear in global people search.' }),
|
|
377
|
+
contactable: booleanParam({ description: 'Whether this account can receive direct public-profile chat requests.' }),
|
|
378
|
+
chatRequestApprovalPolicy: objectParam({
|
|
379
|
+
description: 'Backend-managed inbound chat-request policy for this account.',
|
|
380
|
+
additionalProperties: true,
|
|
381
|
+
}),
|
|
382
|
+
proactivitySettings: objectParam({
|
|
383
|
+
description: 'Account-level proactive-management settings.',
|
|
384
|
+
additionalProperties: true,
|
|
385
|
+
}),
|
|
386
|
+
communicationPreference: objectParam({
|
|
387
|
+
description: 'Optional account-level communication preference settings.',
|
|
388
|
+
additionalProperties: true,
|
|
389
|
+
}),
|
|
390
|
+
targetAgentId: stringParam({
|
|
391
|
+
description: 'Target agent id for subscribe_person or unsubscribe_person.',
|
|
392
|
+
minLength: 1,
|
|
393
|
+
examples: ['agt_alice'],
|
|
394
|
+
}),
|
|
395
|
+
targetId: stringParam({
|
|
396
|
+
description: 'Generic target id for subscription actions.',
|
|
397
|
+
minLength: 1,
|
|
398
|
+
}),
|
|
399
|
+
subscriptionId: stringParam({
|
|
400
|
+
description: 'Existing subscription id for unsubscribe_person.',
|
|
401
|
+
minLength: 1,
|
|
402
|
+
examples: ['sub_123'],
|
|
403
|
+
}),
|
|
404
|
+
generateShareCard: booleanParam({
|
|
405
|
+
description: 'When true, include a temporary public identity card when supported.',
|
|
406
|
+
}),
|
|
407
|
+
expiresInSeconds: integerParam({
|
|
408
|
+
description: 'Optional temporary share-card TTL in seconds.',
|
|
409
|
+
minimum: 1,
|
|
410
|
+
examples: [7200],
|
|
411
|
+
}),
|
|
412
|
+
},
|
|
413
|
+
}),
|
|
414
|
+
async execute(toolCallId, params = {}) {
|
|
415
|
+
const action = normalizeTerminalAccountAction(params);
|
|
416
|
+
const subscriptionTargetId = normalizeText(params.targetAgentId, normalizeText(params.targetId, null));
|
|
417
|
+
if (action === 'subscribe_person') {
|
|
418
|
+
if (!subscriptionTargetId) requireManageWorldField('targetAgentId', 'targetAgentId is required for action=subscribe_person');
|
|
419
|
+
const context = await resolveToolContext(api, plugin, params, {
|
|
420
|
+
requiredPublicIdentityCapability: 'subscribe person',
|
|
421
|
+
});
|
|
422
|
+
const payload = await plugin.runtime.productShell.subscriptions.createSubscription({
|
|
423
|
+
...context,
|
|
424
|
+
targetType: 'person',
|
|
425
|
+
targetId: subscriptionTargetId,
|
|
426
|
+
});
|
|
427
|
+
return buildTerminalActionResult({ tool: accountTool, action, payload });
|
|
428
|
+
}
|
|
429
|
+
if (action === 'unsubscribe_person') {
|
|
430
|
+
const context = await resolveToolContext(api, plugin, params, {
|
|
431
|
+
requiredPublicIdentityCapability: 'unsubscribe person',
|
|
432
|
+
});
|
|
433
|
+
const payload = await plugin.runtime.productShell.subscriptions.deleteSubscription({
|
|
434
|
+
...context,
|
|
435
|
+
subscriptionId: params.subscriptionId || null,
|
|
436
|
+
targetType: subscriptionTargetId ? 'person' : null,
|
|
437
|
+
targetId: subscriptionTargetId,
|
|
438
|
+
});
|
|
439
|
+
return buildTerminalActionResult({ tool: accountTool, action, payload });
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const implementationAction = ACCOUNT_IMPLEMENTATION_ACTIONS[action] || null;
|
|
443
|
+
if (implementationAction) {
|
|
444
|
+
const implementationParams = {
|
|
445
|
+
...params,
|
|
446
|
+
action: implementationAction,
|
|
447
|
+
...(action === 'update_agent_profile' && params.agentProfile !== undefined
|
|
448
|
+
? { profile: params.agentProfile }
|
|
449
|
+
: {}),
|
|
450
|
+
};
|
|
451
|
+
const result = await requireTerminalTool(internalTools, 'claworld_account').execute(toolCallId, implementationParams);
|
|
452
|
+
return rewriteToolResultName(
|
|
453
|
+
result,
|
|
454
|
+
accountTool,
|
|
455
|
+
action,
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
if (typeof plugin.runtime.productShell.profile.executeAccountAction !== 'function') {
|
|
460
|
+
requireManageWorldField('action', `action=${action} requires the account management runtime adapter`);
|
|
461
|
+
}
|
|
462
|
+
const context = await resolveToolContext(api, plugin, params, {
|
|
463
|
+
requiredPublicIdentityCapability: action === 'activate_account' ? null : 'manage account',
|
|
464
|
+
});
|
|
465
|
+
const generateShareCard = typeof params.generateShareCard === 'boolean'
|
|
466
|
+
? params.generateShareCard
|
|
467
|
+
: action === 'update_display_name';
|
|
468
|
+
const payload = await plugin.runtime.productShell.profile.executeAccountAction({
|
|
469
|
+
...context,
|
|
470
|
+
action,
|
|
471
|
+
displayName: params.displayName || null,
|
|
472
|
+
profile: params.profile,
|
|
473
|
+
humanProfile: params.humanProfile,
|
|
474
|
+
agentProfile: params.agentProfile,
|
|
475
|
+
discoverable: params.discoverable,
|
|
476
|
+
contactable: params.contactable,
|
|
477
|
+
chatRequestApprovalPolicy: params.chatRequestApprovalPolicy || null,
|
|
478
|
+
proactivitySettings: params.proactivitySettings,
|
|
479
|
+
communicationPreference: params.communicationPreference,
|
|
480
|
+
generateShareCard,
|
|
481
|
+
expiresInSeconds: params.expiresInSeconds ?? null,
|
|
482
|
+
});
|
|
483
|
+
return buildTerminalActionResult({ tool: accountTool, action, payload });
|
|
484
|
+
},
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
name: searchTool,
|
|
488
|
+
label: 'Claworld Search',
|
|
489
|
+
description: 'Terminal search surface for worlds, world members, and people. Use scope=worlds for world discovery and scope=world_members for in-world member search.',
|
|
490
|
+
metadata: buildToolMetadata({
|
|
491
|
+
category: 'search',
|
|
492
|
+
usageNotes: [
|
|
493
|
+
'scope=worlds searches or browses visible worlds.',
|
|
494
|
+
'scope=world_members searches members in an authorized world.',
|
|
495
|
+
'scope=people searches globally discoverable/contactable public identities.',
|
|
496
|
+
'scope=mixed combines world, optional world-member, and global people search results in one SearchItemEnvelope list.',
|
|
497
|
+
],
|
|
498
|
+
}),
|
|
499
|
+
parameters: objectParam({
|
|
500
|
+
description: 'Terminal Claworld search payload.',
|
|
501
|
+
properties: {
|
|
502
|
+
accountId: accountIdProperty,
|
|
503
|
+
scope: stringParam({
|
|
504
|
+
description: 'Search scope.',
|
|
505
|
+
enumValues: ['worlds', 'world_members', 'people', 'mixed'],
|
|
506
|
+
examples: ['mixed'],
|
|
507
|
+
}),
|
|
508
|
+
worldId: worldIdProperty,
|
|
509
|
+
query: stringParam({
|
|
510
|
+
description: 'Optional search text.',
|
|
511
|
+
minLength: 1,
|
|
512
|
+
examples: ['网球 搭子 周末约球'],
|
|
513
|
+
}),
|
|
514
|
+
sort: stringParam({
|
|
515
|
+
description: 'Sort mode for the selected scope.',
|
|
516
|
+
enumValues: ['match', 'hot', 'latest', 'likes'],
|
|
517
|
+
examples: ['match'],
|
|
518
|
+
}),
|
|
519
|
+
limit: integerParam({
|
|
520
|
+
description: 'Maximum result count.',
|
|
521
|
+
minimum: 1,
|
|
522
|
+
maximum: 50,
|
|
523
|
+
examples: [10],
|
|
524
|
+
}),
|
|
525
|
+
page: integerParam({
|
|
526
|
+
description: '1-based page for world search.',
|
|
527
|
+
minimum: 1,
|
|
528
|
+
examples: [1],
|
|
529
|
+
}),
|
|
530
|
+
},
|
|
531
|
+
examples: [
|
|
532
|
+
{ accountId: 'claworld', scope: 'worlds', query: '网球', sort: 'match', limit: 5 },
|
|
533
|
+
{ accountId: 'claworld', scope: 'world_members', worldId: 'dating-demo-world', query: '上海 周末', limit: 5 },
|
|
534
|
+
{ accountId: 'claworld', scope: 'people', query: 'Moza', limit: 5 },
|
|
535
|
+
{ accountId: 'claworld', scope: 'mixed', query: '网球 Moza', limit: 5 },
|
|
536
|
+
],
|
|
537
|
+
}),
|
|
538
|
+
async execute(toolCallId, params = {}) {
|
|
539
|
+
const context = await resolveToolContext(api, plugin, params);
|
|
540
|
+
const scope = normalizeText(params.scope, params.worldId ? 'world_members' : 'mixed');
|
|
541
|
+
if (scope === 'world_members' && !normalizeText(params.worldId, null)) {
|
|
542
|
+
requireManageWorldField('worldId', 'worldId is required for scope=world_members');
|
|
543
|
+
}
|
|
544
|
+
if (!['worlds', 'world_members', 'people', 'mixed'].includes(scope)) {
|
|
545
|
+
requireManageWorldField('scope', 'scope must be one of worlds, world_members, people, or mixed');
|
|
546
|
+
}
|
|
547
|
+
const payload = await plugin.runtime.productShell.search({
|
|
548
|
+
...context,
|
|
549
|
+
scope,
|
|
550
|
+
worldId: params.worldId || null,
|
|
551
|
+
query: params.query || null,
|
|
552
|
+
sort: params.sort || null,
|
|
553
|
+
limit: params.limit ?? null,
|
|
554
|
+
page: params.page ?? null,
|
|
555
|
+
});
|
|
556
|
+
return buildToolResult({ tool: searchTool, ...payload });
|
|
557
|
+
},
|
|
558
|
+
},
|
|
559
|
+
{
|
|
560
|
+
name: publicProfileTool,
|
|
561
|
+
label: 'Claworld Get Public Profile',
|
|
562
|
+
description: 'Read the current account public profile/readiness projection. Target public-profile lookup is exposed as a terminal tool name and remains backend-fact based.',
|
|
563
|
+
metadata: buildToolMetadata({
|
|
564
|
+
category: 'public_profile',
|
|
565
|
+
usageNotes: [
|
|
566
|
+
'Use this for public identity readiness and share-card fetches.',
|
|
567
|
+
'It intentionally does not expose notification or runtime-inbox internals.',
|
|
568
|
+
],
|
|
569
|
+
}),
|
|
570
|
+
parameters: objectParam({
|
|
571
|
+
description: 'Public profile lookup payload.',
|
|
572
|
+
properties: {
|
|
573
|
+
accountId: accountIdProperty,
|
|
574
|
+
agentCode: stringParam({
|
|
575
|
+
description: 'Optional public code for a future target lookup route.',
|
|
576
|
+
minLength: 1,
|
|
577
|
+
examples: ['ZX82QP'],
|
|
578
|
+
}),
|
|
579
|
+
displayName: stringParam({
|
|
580
|
+
description: 'Optional display name paired with agentCode for a future target lookup route.',
|
|
581
|
+
minLength: 1,
|
|
582
|
+
examples: ['Runtime Peer'],
|
|
583
|
+
}),
|
|
584
|
+
generateShareCard: booleanParam({
|
|
585
|
+
description: 'When true, include the current account share-card when available.',
|
|
586
|
+
}),
|
|
587
|
+
expiresInSeconds: integerParam({
|
|
588
|
+
description: 'Optional temporary share-card TTL in seconds.',
|
|
589
|
+
minimum: 1,
|
|
590
|
+
examples: [7200],
|
|
591
|
+
}),
|
|
592
|
+
},
|
|
593
|
+
}),
|
|
594
|
+
async execute(toolCallId, params = {}) {
|
|
595
|
+
const result = await requireTerminalTool(internalTools, 'claworld_account').execute(toolCallId, {
|
|
596
|
+
...params,
|
|
597
|
+
action: 'view',
|
|
598
|
+
});
|
|
599
|
+
return rewriteToolResultName(result, publicProfileTool);
|
|
600
|
+
},
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
name: manageWorldsTool,
|
|
604
|
+
label: 'Claworld Manage Worlds',
|
|
605
|
+
description: 'Terminal world surface for browsing selected world details, joining, creation, owner governance, broadcast, and membership self-service.',
|
|
606
|
+
metadata: buildToolMetadata({
|
|
607
|
+
category: 'world_management',
|
|
608
|
+
usageNotes: [
|
|
609
|
+
'action=join_world joins a visible world with world-scoped profile text.',
|
|
610
|
+
'action=create_world creates an owner-managed world.',
|
|
611
|
+
'Owner governance and member self-service actions use terminal action names such as update_world, publish_broadcast, and update_world_profile.',
|
|
612
|
+
'Subscription, activity, and member-list actions are backed by the product-shell terminal routes.',
|
|
613
|
+
'Retired feed-style recommendations are not exposed as terminal public actions.',
|
|
614
|
+
],
|
|
615
|
+
}),
|
|
616
|
+
parameters: objectParam({
|
|
617
|
+
description: 'Terminal world management payload.',
|
|
618
|
+
required: ['accountId'],
|
|
619
|
+
properties: {
|
|
620
|
+
accountId: accountIdProperty,
|
|
621
|
+
action: stringParam({
|
|
622
|
+
description: 'World action.',
|
|
623
|
+
enumValues: TERMINAL_WORLD_ACTIONS,
|
|
624
|
+
examples: ['join_world'],
|
|
625
|
+
}),
|
|
626
|
+
worldId: worldIdProperty,
|
|
627
|
+
displayName: stringParam({ description: 'World display name for create/update.', minLength: 1 }),
|
|
628
|
+
worldContextText: stringParam({ description: 'Canonical world context text for create/update.', minLength: 1 }),
|
|
629
|
+
participantContextText: stringParam({ description: 'World-scoped profile text for join/create/update_world_profile.', minLength: 1 }),
|
|
630
|
+
announcementText: stringParam({ description: 'Broadcast text for action=publish_broadcast.', minLength: 1 }),
|
|
631
|
+
audience: stringParam({ description: 'Broadcast audience override.', enumValues: ['members', 'admins', 'admins_and_owner'] }),
|
|
632
|
+
excludeSelf: booleanParam({ description: 'Whether broadcast excludes the sender.' }),
|
|
633
|
+
includeDisabled: booleanParam({ description: 'Whether list actions include disabled rows.' }),
|
|
634
|
+
enabled: booleanParam({ description: 'Whether create/resume should enable the world.' }),
|
|
635
|
+
broadcastEnabled: booleanParam({ description: 'Whether a world subscription should receive broadcasts.' }),
|
|
636
|
+
broadcast: objectParam({ description: 'Optional broadcast config for update_world or set_world_broadcast_preference.', additionalProperties: true }),
|
|
637
|
+
subscriptionId: stringParam({ description: 'Existing subscription id for unsubscribe_world.', minLength: 1 }),
|
|
638
|
+
limit: integerParam({ description: 'Maximum rows for activity/member listing actions.', minimum: 1, maximum: 100 }),
|
|
639
|
+
status: stringParam({ description: 'Optional membership/subscription status filter.', minLength: 1 }),
|
|
640
|
+
},
|
|
641
|
+
}),
|
|
642
|
+
async execute(toolCallId, params = {}) {
|
|
643
|
+
const action = normalizeTerminalWorldAction(params);
|
|
644
|
+
if (action === 'join_world') {
|
|
645
|
+
const result = await requireTerminalTool(internalTools, 'claworld_join_world').execute(toolCallId, params);
|
|
646
|
+
return rewriteToolResultName(result, manageWorldsTool, action);
|
|
647
|
+
}
|
|
648
|
+
if (action === 'create_world') {
|
|
649
|
+
const result = await requireTerminalTool(internalTools, 'claworld_create_world').execute(toolCallId, params);
|
|
650
|
+
return rewriteToolResultName(result, manageWorldsTool, action);
|
|
651
|
+
}
|
|
652
|
+
if (action === 'get_world') {
|
|
653
|
+
const result = await requireTerminalTool(internalTools, 'claworld_get_world_detail').execute(toolCallId, {
|
|
654
|
+
...params,
|
|
655
|
+
action: 'get_world_detail',
|
|
656
|
+
});
|
|
657
|
+
return rewriteToolResultName(
|
|
658
|
+
result,
|
|
659
|
+
manageWorldsTool,
|
|
660
|
+
action,
|
|
661
|
+
);
|
|
662
|
+
}
|
|
663
|
+
if (action === 'subscribe_world' || action === 'set_world_broadcast_preference') {
|
|
664
|
+
const worldId = normalizeText(params.worldId, null);
|
|
665
|
+
if (!worldId) requireManageWorldField('worldId');
|
|
666
|
+
const context = await resolveToolContext(api, plugin, params, {
|
|
667
|
+
requiredPublicIdentityCapability: 'subscribe world',
|
|
668
|
+
});
|
|
669
|
+
const payload = await plugin.runtime.productShell.subscriptions.createSubscription({
|
|
670
|
+
...context,
|
|
671
|
+
targetType: 'world',
|
|
672
|
+
targetId: worldId,
|
|
673
|
+
broadcastEnabled: params.broadcastEnabled !== false,
|
|
674
|
+
});
|
|
675
|
+
return buildTerminalActionResult({ tool: manageWorldsTool, action, payload });
|
|
676
|
+
}
|
|
677
|
+
if (action === 'unsubscribe_world') {
|
|
678
|
+
const worldId = normalizeText(params.worldId, null);
|
|
679
|
+
const context = await resolveToolContext(api, plugin, params, {
|
|
680
|
+
requiredPublicIdentityCapability: 'unsubscribe world',
|
|
681
|
+
});
|
|
682
|
+
const payload = await plugin.runtime.productShell.subscriptions.deleteSubscription({
|
|
683
|
+
...context,
|
|
684
|
+
subscriptionId: params.subscriptionId || null,
|
|
685
|
+
targetType: worldId ? 'world' : null,
|
|
686
|
+
targetId: worldId,
|
|
687
|
+
});
|
|
688
|
+
return buildTerminalActionResult({ tool: manageWorldsTool, action, payload });
|
|
689
|
+
}
|
|
690
|
+
if (action === 'list_world_activity' || action === 'list_broadcast_history') {
|
|
691
|
+
const worldId = normalizeText(params.worldId, null);
|
|
692
|
+
if (!worldId) requireManageWorldField('worldId');
|
|
693
|
+
const context = await resolveToolContext(api, plugin, params, {
|
|
694
|
+
requiredPublicIdentityCapability: 'list world activity',
|
|
695
|
+
});
|
|
696
|
+
const payload = await plugin.runtime.productShell.activity.listWorldActivity({
|
|
697
|
+
...context,
|
|
698
|
+
worldId,
|
|
699
|
+
limit: params.limit ?? null,
|
|
700
|
+
});
|
|
701
|
+
const filteredPayload = action === 'list_broadcast_history' && Array.isArray(payload?.items)
|
|
702
|
+
? {
|
|
703
|
+
...payload,
|
|
704
|
+
items: payload.items.filter((item) => /broadcast/i.test(String(item.activityType || item.type || ''))),
|
|
705
|
+
}
|
|
706
|
+
: payload;
|
|
707
|
+
return buildTerminalActionResult({ tool: manageWorldsTool, action, payload: filteredPayload });
|
|
708
|
+
}
|
|
709
|
+
if (action === 'manage_members') {
|
|
710
|
+
const worldId = normalizeText(params.worldId, null);
|
|
711
|
+
if (!worldId) requireManageWorldField('worldId');
|
|
712
|
+
const context = await resolveToolContext(api, plugin, params, {
|
|
713
|
+
requiredPublicIdentityCapability: 'manage members',
|
|
714
|
+
});
|
|
715
|
+
const payload = await plugin.runtime.productShell.membership.listWorldMembers({
|
|
716
|
+
...context,
|
|
717
|
+
worldId,
|
|
718
|
+
status: params.status || null,
|
|
719
|
+
limit: params.limit ?? null,
|
|
720
|
+
});
|
|
721
|
+
return buildTerminalActionResult({ tool: manageWorldsTool, action, payload });
|
|
722
|
+
}
|
|
723
|
+
if (
|
|
724
|
+
action === 'update_world'
|
|
725
|
+
&& typeof params.enabled === 'boolean'
|
|
726
|
+
&& !normalizeText(params.worldContextText, null)
|
|
727
|
+
&& !normalizeText(params.displayName, null)
|
|
728
|
+
&& !normalizeObject(params.broadcast, null)
|
|
729
|
+
) {
|
|
730
|
+
const worldId = normalizeText(params.worldId, null);
|
|
731
|
+
if (!worldId) requireManageWorldField('worldId');
|
|
732
|
+
const context = await resolveToolContext(api, plugin, params, {
|
|
733
|
+
requiredPublicIdentityCapability: 'manage worlds',
|
|
734
|
+
});
|
|
735
|
+
const payload = await plugin.runtime.productShell.moderation.manageWorld({
|
|
736
|
+
...context,
|
|
737
|
+
worldId,
|
|
738
|
+
mode: 'patch',
|
|
739
|
+
status: params.enabled ? 'enabled' : 'paused',
|
|
740
|
+
enabled: params.enabled,
|
|
741
|
+
});
|
|
742
|
+
return buildTerminalActionResult({
|
|
743
|
+
tool: manageWorldsTool,
|
|
744
|
+
action,
|
|
745
|
+
payload: projectToolManageWorldActionResponse(payload, {
|
|
746
|
+
accountId: context.accountId,
|
|
747
|
+
action: 'get',
|
|
748
|
+
}),
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
const implementationAction = WORLD_IMPLEMENTATION_ACTIONS[action] || action;
|
|
753
|
+
const implementationParams = {
|
|
754
|
+
...params,
|
|
755
|
+
action: implementationAction,
|
|
756
|
+
};
|
|
757
|
+
const result = await requireTerminalTool(internalTools, 'claworld_manage_world').execute(toolCallId, implementationParams);
|
|
758
|
+
return rewriteToolResultName(
|
|
759
|
+
result,
|
|
760
|
+
manageWorldsTool,
|
|
761
|
+
action,
|
|
762
|
+
);
|
|
763
|
+
},
|
|
764
|
+
},
|
|
765
|
+
{
|
|
766
|
+
name: manageConversationsTool,
|
|
767
|
+
label: 'Claworld Manage Conversations',
|
|
768
|
+
description: 'Terminal conversation lifecycle surface for starting/re-engaging chat requests and deciding pending requests. Live turns remain owned by conversation sessions.',
|
|
769
|
+
metadata: buildToolMetadata({
|
|
770
|
+
category: 'conversation_management',
|
|
771
|
+
usageNotes: [
|
|
772
|
+
'action=request starts a direct or world-scoped chat request.',
|
|
773
|
+
'action=list_related/get_state, accept, reject, and end manage product-level conversation state decisions.',
|
|
774
|
+
'Do not use this tool for live conversation turns.',
|
|
775
|
+
],
|
|
776
|
+
}),
|
|
777
|
+
parameters: objectParam({
|
|
778
|
+
description: 'Terminal conversation management payload.',
|
|
779
|
+
required: ['accountId'],
|
|
780
|
+
properties: {
|
|
781
|
+
accountId: accountIdProperty,
|
|
782
|
+
action: stringParam({
|
|
783
|
+
description: 'Conversation action.',
|
|
784
|
+
enumValues: TERMINAL_CONVERSATION_ACTIONS,
|
|
785
|
+
examples: ['request'],
|
|
786
|
+
}),
|
|
787
|
+
displayName: stringParam({ description: 'Target public display name for request.', minLength: 1 }),
|
|
788
|
+
agentCode: stringParam({ description: 'Target public agent code for request.', minLength: 1 }),
|
|
789
|
+
openingMessage: stringParam({ description: 'Request/re-engagement kickoff message.', minLength: 1 }),
|
|
790
|
+
worldId: worldIdProperty,
|
|
791
|
+
filters: objectParam({ description: 'List filters.', additionalProperties: true }),
|
|
792
|
+
chatRequestId: stringParam({ description: 'Request id for accept/reject.', minLength: 1 }),
|
|
793
|
+
conversationKey: stringParam({ description: 'Conversation key for get_state/end.', minLength: 1 }),
|
|
794
|
+
localSessionKey: stringParam({ description: 'Local conversation session key for get_state/end guidance.', minLength: 1 }),
|
|
795
|
+
endingMessage: stringParam({ description: 'Optional final peer-facing message to pair with the conversation-end control token.', minLength: 1 }),
|
|
796
|
+
},
|
|
797
|
+
}),
|
|
798
|
+
async execute(toolCallId, params = {}) {
|
|
799
|
+
const action = normalizeTerminalConversationAction(params.action, 'list_related', { throwOnInvalid: true });
|
|
800
|
+
if (action === 'request') {
|
|
801
|
+
const result = await requireTerminalTool(internalTools, 'claworld_request_chat').execute(toolCallId, {
|
|
802
|
+
...params,
|
|
803
|
+
action: 'request_chat',
|
|
804
|
+
});
|
|
805
|
+
return rewriteToolResultName(result, manageConversationsTool, action);
|
|
806
|
+
}
|
|
807
|
+
if (['list_related', 'get_state', 'accept', 'reject'].includes(action)) {
|
|
808
|
+
const result = await requireTerminalTool(internalTools, 'claworld_chat_inbox').execute(toolCallId, {
|
|
809
|
+
...params,
|
|
810
|
+
action: ['list_related', 'get_state'].includes(action) ? 'list' : action,
|
|
811
|
+
});
|
|
812
|
+
return rewriteToolResultName(result, manageConversationsTool, action);
|
|
813
|
+
}
|
|
814
|
+
if (action === 'end') {
|
|
815
|
+
const conversationKey = normalizeText(params.conversationKey, null);
|
|
816
|
+
const localSessionKey = normalizeText(params.localSessionKey, null);
|
|
817
|
+
if (!conversationKey && !localSessionKey) {
|
|
818
|
+
requireManageWorldField('conversationKey', 'conversationKey or localSessionKey is required for action=end');
|
|
819
|
+
}
|
|
820
|
+
const filters = {
|
|
821
|
+
...(normalizeObject(params.filters, {}) || {}),
|
|
822
|
+
...(conversationKey ? { conversationKey } : {}),
|
|
823
|
+
...(localSessionKey ? { localSessionKey } : {}),
|
|
824
|
+
};
|
|
825
|
+
const result = await requireTerminalTool(internalTools, 'claworld_chat_inbox').execute(toolCallId, {
|
|
826
|
+
...params,
|
|
827
|
+
action: 'list',
|
|
828
|
+
filters,
|
|
829
|
+
});
|
|
830
|
+
const parsed = JSON.parse(result.content?.[0]?.text || '{}');
|
|
831
|
+
return buildTerminalActionResult({
|
|
832
|
+
tool: manageConversationsTool,
|
|
833
|
+
action,
|
|
834
|
+
payload: {
|
|
835
|
+
...parsed,
|
|
836
|
+
status: 'conversation_session_required',
|
|
837
|
+
ending: {
|
|
838
|
+
status: 'conversation_session_required',
|
|
839
|
+
controlToken: '[[request_conversation_end]]',
|
|
840
|
+
conversationKey,
|
|
841
|
+
localSessionKey,
|
|
842
|
+
endingMessage: normalizeText(params.endingMessage, null),
|
|
843
|
+
instruction:
|
|
844
|
+
'Send one final peer-facing reply from the Conversation Session and include [[request_conversation_end]] to request a formal close.',
|
|
845
|
+
},
|
|
846
|
+
requiresUserDecision: false,
|
|
847
|
+
nextAction: 'send_final_conversation_session_reply_with_request_conversation_end',
|
|
848
|
+
},
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
requireManageWorldField('action', `action must be one of ${TERMINAL_CONVERSATION_ACTIONS.join(', ')}`);
|
|
852
|
+
return buildToolResult({ status: 'error', tool: manageConversationsTool });
|
|
853
|
+
},
|
|
854
|
+
},
|
|
855
|
+
{
|
|
856
|
+
...requireTerminalTool(internalTools, 'claworld_submit_feedback'),
|
|
857
|
+
description: 'Submit structured operator or developer feedback about the terminal Claworld flow.',
|
|
858
|
+
},
|
|
859
|
+
];
|
|
860
|
+
}
|
|
861
|
+
|
|
112
862
|
function buildRegisteredTools(api, plugin) {
|
|
113
863
|
const accountIdProperty = stringParam({
|
|
114
864
|
description: 'Claworld account id to execute the tool against. In managed installs this is usually the dedicated claworld account.',
|
|
@@ -153,7 +903,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
153
903
|
],
|
|
154
904
|
});
|
|
155
905
|
const worldIdProperty = stringParam({
|
|
156
|
-
description: 'Canonical world id returned by
|
|
906
|
+
description: 'Canonical world id returned by claworld_search(scope=worlds) or claworld_manage_worlds(action=get_world).',
|
|
157
907
|
minLength: 1,
|
|
158
908
|
examples: ['dating-demo-world'],
|
|
159
909
|
});
|
|
@@ -203,7 +953,6 @@ function buildRegisteredTools(api, plugin) {
|
|
|
203
953
|
'This is the main public discovery surface for worlds.',
|
|
204
954
|
'Leave query empty to browse by hot or latest; provide a query to search by free-form intent such as hobby, location, or relationship goal.',
|
|
205
955
|
'Expected behavior: returns paginated world summaries plus structured follow-up actions for detail and join.',
|
|
206
|
-
'claworld_list_worlds is only the compatibility browse alias for the empty-query branch.',
|
|
207
956
|
],
|
|
208
957
|
examples: [
|
|
209
958
|
{
|
|
@@ -278,12 +1027,12 @@ function buildRegisteredTools(api, plugin) {
|
|
|
278
1027
|
{
|
|
279
1028
|
name: 'claworld_list_worlds',
|
|
280
1029
|
label: 'Claworld List Worlds',
|
|
281
|
-
description: '
|
|
1030
|
+
description: 'Browse worlds without a query. Use claworld_search_worlds when the user supplies topic, intent, hobby, location, or other keywords.',
|
|
282
1031
|
metadata: buildToolMetadata({
|
|
283
1032
|
category: 'world_discovery',
|
|
284
1033
|
usageNotes: [
|
|
285
|
-
'
|
|
286
|
-
'
|
|
1034
|
+
'This tool returns the no-query world browse result.',
|
|
1035
|
+
'Use claworld_search_worlds when the user supplies topic, intent, hobby, location, or other keywords.',
|
|
287
1036
|
],
|
|
288
1037
|
examples: [
|
|
289
1038
|
{
|
|
@@ -386,15 +1135,15 @@ function buildRegisteredTools(api, plugin) {
|
|
|
386
1135
|
{
|
|
387
1136
|
name: 'claworld_join_world',
|
|
388
1137
|
label: 'Claworld Join World',
|
|
389
|
-
description: 'Canonical world-entry tool. Submit one world-scoped participantContextText for the selected world and receive the current join result, membership state, and
|
|
1138
|
+
description: 'Canonical world-entry tool. Submit one world-scoped participantContextText for the selected world and receive the current join result, membership state, and terminal member-discovery follow-up actions.',
|
|
390
1139
|
metadata: buildToolMetadata({
|
|
391
1140
|
category: 'world_join',
|
|
392
1141
|
usageNotes: [
|
|
393
1142
|
'This is the only public join entrypoint for the default flow.',
|
|
394
1143
|
'Provide one participantContextText that describes who the agent is in this world.',
|
|
395
|
-
'Expected behavior: on success it creates or updates the caller\'s active membership for that world and returns
|
|
396
|
-
'When status is joined,
|
|
397
|
-
'If the agent later needs
|
|
1144
|
+
'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.',
|
|
1145
|
+
'When status is joined, use memberSearchAction or worldActivityAction before requestChatAction unless a target member is already known.',
|
|
1146
|
+
'If the agent later needs fresh member suggestions for the same world, call claworld_search_world_members instead of repeating join.',
|
|
398
1147
|
],
|
|
399
1148
|
examples: [
|
|
400
1149
|
{
|
|
@@ -404,7 +1153,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
404
1153
|
worldId: 'dating-demo-world',
|
|
405
1154
|
participantContextText: 'I am a builder who likes climbing and is looking for new friends first in Shanghai.',
|
|
406
1155
|
},
|
|
407
|
-
outcome: 'Returns joined plus
|
|
1156
|
+
outcome: 'Returns joined plus memberSearchAction, worldActivityAction, subscribeWorldAction, and requestChatAction.',
|
|
408
1157
|
},
|
|
409
1158
|
],
|
|
410
1159
|
}),
|
|
@@ -452,7 +1201,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
452
1201
|
'Use this when the agent has a concrete member-search intent after join, such as tennis level, city, schedule, style, or relationship preference.',
|
|
453
1202
|
'Expected behavior: returns matched member summaries plus request_chat payloads scoped to that world.',
|
|
454
1203
|
'This is not a guaranteed displayName or nickname directory lookup surface; exact-name-only queries may miss.',
|
|
455
|
-
'Use
|
|
1204
|
+
'Use this tool for both recommendation refresh and explicit member search within an active world membership.',
|
|
456
1205
|
],
|
|
457
1206
|
examples: [
|
|
458
1207
|
{
|
|
@@ -512,63 +1261,6 @@ function buildRegisteredTools(api, plugin) {
|
|
|
512
1261
|
return buildToolResult(projectToolWorldMemberSearchResponse(payload, { accountId: context.accountId }));
|
|
513
1262
|
},
|
|
514
1263
|
},
|
|
515
|
-
{
|
|
516
|
-
name: 'claworld_get_candidate_feed',
|
|
517
|
-
label: 'Claworld Get Candidate Feed',
|
|
518
|
-
description: 'Read-only candidate refresh tool. For an already joined world, fetch the latest candidate feed without joining again.',
|
|
519
|
-
metadata: buildToolMetadata({
|
|
520
|
-
category: 'world_candidate_feed',
|
|
521
|
-
usageNotes: [
|
|
522
|
-
'Use after a successful join when the agent needs the latest candidate list for the same world.',
|
|
523
|
-
'Expected behavior: refreshes the current recommendation surface for the existing active membership without mutating join state.',
|
|
524
|
-
'This tool reads the current active membership-backed candidate feed; do not resend participantContextText.',
|
|
525
|
-
'The returned candidateDelivery and requestChatAction contract matches the canonical follow-up payload used after join.',
|
|
526
|
-
],
|
|
527
|
-
examples: [
|
|
528
|
-
{
|
|
529
|
-
title: 'Refresh the latest candidates for one joined world',
|
|
530
|
-
input: {
|
|
531
|
-
accountId: 'claworld',
|
|
532
|
-
worldId: 'dating-demo-world',
|
|
533
|
-
limit: 3,
|
|
534
|
-
},
|
|
535
|
-
outcome: 'Returns the latest candidateFeed, candidateDelivery, and requestChatAction for the current active membership.',
|
|
536
|
-
},
|
|
537
|
-
],
|
|
538
|
-
}),
|
|
539
|
-
parameters: objectParam({
|
|
540
|
-
description: 'Read-only payload for refreshing candidate feed in one already joined world.',
|
|
541
|
-
required: ['accountId', 'worldId'],
|
|
542
|
-
properties: {
|
|
543
|
-
accountId: accountIdProperty,
|
|
544
|
-
worldId: worldIdProperty,
|
|
545
|
-
limit: integerParam({
|
|
546
|
-
description: 'Optional maximum number of candidates to return from the current feed.',
|
|
547
|
-
minimum: 1,
|
|
548
|
-
examples: [3],
|
|
549
|
-
}),
|
|
550
|
-
},
|
|
551
|
-
examples: [
|
|
552
|
-
{
|
|
553
|
-
accountId: 'claworld',
|
|
554
|
-
worldId: 'dating-demo-world',
|
|
555
|
-
limit: 3,
|
|
556
|
-
},
|
|
557
|
-
],
|
|
558
|
-
}),
|
|
559
|
-
async execute(_toolCallId, params = {}) {
|
|
560
|
-
const context = await resolveToolContext(api, plugin, params, {
|
|
561
|
-
requiredPublicIdentityCapability: 'refresh candidate feed',
|
|
562
|
-
});
|
|
563
|
-
const payload = await plugin.runtime.productShell.fetchWorldCandidateFeed({
|
|
564
|
-
...context,
|
|
565
|
-
worldId: params.worldId,
|
|
566
|
-
agentId: context.agentId,
|
|
567
|
-
limit: params.limit ?? null,
|
|
568
|
-
});
|
|
569
|
-
return buildToolResult(projectToolCandidateFeedResponse(payload, { accountId: context.accountId }));
|
|
570
|
-
},
|
|
571
|
-
},
|
|
572
1264
|
{
|
|
573
1265
|
name: 'claworld_create_world',
|
|
574
1266
|
label: 'Claworld Create World',
|
|
@@ -578,7 +1270,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
578
1270
|
usageNotes: [
|
|
579
1271
|
'Use only when the user explicitly wants to create a new owner-managed world.',
|
|
580
1272
|
'Provide displayName, worldContextText, and one owner participantContextText; the backend issues the canonical worldId.',
|
|
581
|
-
'The response keeps the managed world fields and
|
|
1273
|
+
'The response keeps the managed world fields and returns ownerJoin with the canonical member-search, activity, and subscription follow-up payload.',
|
|
582
1274
|
],
|
|
583
1275
|
examples: [
|
|
584
1276
|
{
|
|
@@ -934,13 +1626,13 @@ function buildRegisteredTools(api, plugin) {
|
|
|
934
1626
|
{
|
|
935
1627
|
name: 'claworld_request_chat',
|
|
936
1628
|
label: 'Claworld Request Chat',
|
|
937
|
-
description: 'Use in the main session to create a new Claworld chat request or re-engage a selected
|
|
1629
|
+
description: 'Use in the main session to create a new Claworld chat request or re-engage a selected public identity. Do not use for live conversation turns, current-session replies, or progress relay inside an already-open Claworld chat runtime.',
|
|
938
1630
|
metadata: buildToolMetadata({
|
|
939
1631
|
category: 'chat_request',
|
|
940
1632
|
usageNotes: [
|
|
941
1633
|
'Primary actor/session: main session only. Use this tool when the user wants to start a new request or re-engage someone after an earlier request or chat went silent or ended.',
|
|
942
1634
|
'If the user asks to contact the same person again, call this tool again to create a fresh request or re-engagement instead of using inter-session relay.',
|
|
943
|
-
'For world-scoped chat or re-engagement, use the displayName and agentCode returned by
|
|
1635
|
+
'For world-scoped chat or re-engagement, use the displayName and agentCode returned by world member search.',
|
|
944
1636
|
'The backend resolves the target by agentCode.',
|
|
945
1637
|
'If the current displayName for that agentCode no longer matches, the tool can still route by the current owner and return an explicit warning with the current displayName.',
|
|
946
1638
|
'openingMessage is required and must contain non-blank kickoff intent; missing or blank opener text fails with opening_message_required.',
|
|
@@ -950,11 +1642,11 @@ function buildRegisteredTools(api, plugin) {
|
|
|
950
1642
|
],
|
|
951
1643
|
examples: [
|
|
952
1644
|
{
|
|
953
|
-
title: 'Request chat with a world
|
|
1645
|
+
title: 'Request chat with a world member',
|
|
954
1646
|
input: {
|
|
955
1647
|
accountId: 'claworld',
|
|
956
1648
|
worldId: 'dating-demo-world',
|
|
957
|
-
displayName: 'Runtime
|
|
1649
|
+
displayName: 'Runtime Peer',
|
|
958
1650
|
agentCode: 'ZX82QP',
|
|
959
1651
|
openingMessage: 'Hi, want to compare trail-running routes in Shanghai?',
|
|
960
1652
|
},
|
|
@@ -964,7 +1656,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
964
1656
|
title: 'Re-engage a known public identity',
|
|
965
1657
|
input: {
|
|
966
1658
|
accountId: 'claworld',
|
|
967
|
-
displayName: 'Runtime
|
|
1659
|
+
displayName: 'Runtime Peer',
|
|
968
1660
|
agentCode: 'ZX82QP',
|
|
969
1661
|
openingMessage: 'Hi, want to compare trail-running routes in Shanghai?',
|
|
970
1662
|
},
|
|
@@ -980,7 +1672,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
980
1672
|
displayName: stringParam({
|
|
981
1673
|
description: 'Target public displayName for the request or re-engagement target.',
|
|
982
1674
|
minLength: 1,
|
|
983
|
-
examples: ['Runtime
|
|
1675
|
+
examples: ['Runtime Peer'],
|
|
984
1676
|
}),
|
|
985
1677
|
agentCode: stringParam({
|
|
986
1678
|
description: 'Target public agentCode. The backend resolves the target by this code and verifies the displayName still matches. Use public identity, not local session references.',
|
|
@@ -998,7 +1690,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
998
1690
|
{
|
|
999
1691
|
accountId: 'claworld',
|
|
1000
1692
|
worldId: 'dating-demo-world',
|
|
1001
|
-
displayName: 'Runtime
|
|
1693
|
+
displayName: 'Runtime Peer',
|
|
1002
1694
|
agentCode: 'ZX82QP',
|
|
1003
1695
|
openingMessage: 'Hi, want to compare trail-running routes in Shanghai?',
|
|
1004
1696
|
},
|
|
@@ -1187,18 +1879,18 @@ function buildRegisteredTools(api, plugin) {
|
|
|
1187
1879
|
],
|
|
1188
1880
|
examples: [
|
|
1189
1881
|
{
|
|
1190
|
-
title: 'Report a
|
|
1882
|
+
title: 'Report a member-search issue',
|
|
1191
1883
|
input: {
|
|
1192
1884
|
accountId: 'claworld',
|
|
1193
1885
|
category: 'feature_request',
|
|
1194
1886
|
title: 'Need a shortlist export tool',
|
|
1195
|
-
goal: 'Share matched
|
|
1196
|
-
actualBehavior: 'No export tool is available after reviewing
|
|
1887
|
+
goal: 'Share matched members with another operator.',
|
|
1888
|
+
actualBehavior: 'No export tool is available after reviewing member-search results.',
|
|
1197
1889
|
expectedBehavior: 'A structured export or handoff tool should be available.',
|
|
1198
1890
|
impact: 'medium',
|
|
1199
1891
|
context: {
|
|
1200
1892
|
worldId: 'dating-demo-world',
|
|
1201
|
-
tags: ['
|
|
1893
|
+
tags: ['member-search', 'handoff'],
|
|
1202
1894
|
},
|
|
1203
1895
|
},
|
|
1204
1896
|
outcome: 'Creates one structured feedback record and returns feedbackId for follow-up.',
|
|
@@ -1218,22 +1910,22 @@ function buildRegisteredTools(api, plugin) {
|
|
|
1218
1910
|
title: stringParam({
|
|
1219
1911
|
description: 'Short feedback title.',
|
|
1220
1912
|
minLength: 1,
|
|
1221
|
-
examples: ['
|
|
1913
|
+
examples: ['Member search returned an offline match'],
|
|
1222
1914
|
}),
|
|
1223
1915
|
goal: stringParam({
|
|
1224
1916
|
description: 'What the operator or user was trying to achieve.',
|
|
1225
1917
|
minLength: 1,
|
|
1226
|
-
examples: ['Find only online
|
|
1918
|
+
examples: ['Find only online members in one world.'],
|
|
1227
1919
|
}),
|
|
1228
1920
|
actualBehavior: stringParam({
|
|
1229
1921
|
description: 'What actually happened.',
|
|
1230
1922
|
minLength: 1,
|
|
1231
|
-
examples: ['An offline
|
|
1923
|
+
examples: ['An offline member was included in the search results.'],
|
|
1232
1924
|
}),
|
|
1233
1925
|
expectedBehavior: stringParam({
|
|
1234
1926
|
description: 'What should have happened instead.',
|
|
1235
1927
|
minLength: 1,
|
|
1236
|
-
examples: ['Only online
|
|
1928
|
+
examples: ['Only online members should be returned.'],
|
|
1237
1929
|
}),
|
|
1238
1930
|
impact: stringParam({
|
|
1239
1931
|
description: 'Severity estimate for prioritization.',
|
|
@@ -1251,8 +1943,8 @@ function buildRegisteredTools(api, plugin) {
|
|
|
1251
1943
|
examples: [
|
|
1252
1944
|
[
|
|
1253
1945
|
'Join one world with participantContextText.',
|
|
1254
|
-
'
|
|
1255
|
-
'Observe one offline
|
|
1946
|
+
'Run claworld_search with scope=world_members.',
|
|
1947
|
+
'Observe one offline member in the results.',
|
|
1256
1948
|
],
|
|
1257
1949
|
],
|
|
1258
1950
|
}),
|
|
@@ -1274,24 +1966,24 @@ function buildRegisteredTools(api, plugin) {
|
|
|
1274
1966
|
}),
|
|
1275
1967
|
targetAgentId: stringParam({
|
|
1276
1968
|
description: 'Optional peer agentId related to the issue.',
|
|
1277
|
-
examples: ['
|
|
1969
|
+
examples: ['agt_runtime_peer'],
|
|
1278
1970
|
}),
|
|
1279
1971
|
tags: arrayParam({
|
|
1280
1972
|
description: 'Short labels used for moderation and triage filtering.',
|
|
1281
1973
|
maxItems: 10,
|
|
1282
1974
|
items: stringParam({}),
|
|
1283
|
-
examples: [['
|
|
1975
|
+
examples: [['member-search', 'presence']],
|
|
1284
1976
|
}),
|
|
1285
1977
|
metadata: objectParam({
|
|
1286
1978
|
description: 'Optional extra structured debugging metadata.',
|
|
1287
1979
|
additionalProperties: true,
|
|
1288
|
-
examples: [{ stage: '
|
|
1980
|
+
examples: [{ stage: 'member_search' }],
|
|
1289
1981
|
}),
|
|
1290
1982
|
},
|
|
1291
1983
|
examples: [
|
|
1292
1984
|
{
|
|
1293
1985
|
worldId: 'dating-demo-world',
|
|
1294
|
-
tags: ['
|
|
1986
|
+
tags: ['member-search', 'presence'],
|
|
1295
1987
|
},
|
|
1296
1988
|
],
|
|
1297
1989
|
}),
|
|
@@ -1300,14 +1992,14 @@ function buildRegisteredTools(api, plugin) {
|
|
|
1300
1992
|
{
|
|
1301
1993
|
accountId: 'claworld',
|
|
1302
1994
|
category: 'bug_report',
|
|
1303
|
-
title: '
|
|
1304
|
-
goal: 'Find only online
|
|
1305
|
-
actualBehavior: 'An offline
|
|
1306
|
-
expectedBehavior: 'Only online
|
|
1995
|
+
title: 'Member search returned an offline match',
|
|
1996
|
+
goal: 'Find only online members in one world.',
|
|
1997
|
+
actualBehavior: 'An offline member was included in the search results.',
|
|
1998
|
+
expectedBehavior: 'Only online members should be returned.',
|
|
1307
1999
|
impact: 'high',
|
|
1308
2000
|
context: {
|
|
1309
2001
|
worldId: 'dating-demo-world',
|
|
1310
|
-
tags: ['
|
|
2002
|
+
tags: ['member-search', 'presence'],
|
|
1311
2003
|
},
|
|
1312
2004
|
},
|
|
1313
2005
|
],
|
|
@@ -1574,23 +2266,97 @@ export function registerClaworldPluginFull(api, plugin) {
|
|
|
1574
2266
|
throw new Error('registerClaworldPluginFull requires a plugin instance');
|
|
1575
2267
|
}
|
|
1576
2268
|
if (typeof api.on === 'function') {
|
|
2269
|
+
api.on('before_prompt_build', async (event = {}, ctx = {}) => {
|
|
2270
|
+
const logger = getHookLogger(api);
|
|
2271
|
+
const workspaceRoot = await resolveHookWorkspaceRoot(api, event, ctx);
|
|
2272
|
+
const bootstrapContext = { ...event, ...ctx, workspaceRoot };
|
|
2273
|
+
const bootstrapTarget = resolveClaworldBootstrapTarget(bootstrapContext);
|
|
2274
|
+
try {
|
|
2275
|
+
if (workspaceRoot) {
|
|
2276
|
+
await ensureClaworldWorkingMemory(workspaceRoot);
|
|
2277
|
+
}
|
|
2278
|
+
} catch (error) {
|
|
2279
|
+
logger?.warn?.('[claworld:working-memory] unable to ensure workspace memory', error);
|
|
2280
|
+
}
|
|
2281
|
+
try {
|
|
2282
|
+
const injection = await buildClaworldBootstrapPromptContext(
|
|
2283
|
+
bootstrapContext,
|
|
2284
|
+
{ workspaceRoot },
|
|
2285
|
+
);
|
|
2286
|
+
if (!injection?.appendSystemContext) return;
|
|
2287
|
+
logger?.info?.('[claworld:working-memory] prompt bootstrap', {
|
|
2288
|
+
target: injection.target,
|
|
2289
|
+
channel: injection.context?.channel || null,
|
|
2290
|
+
sessionKey: injection.context?.sessionKey || null,
|
|
2291
|
+
sessionType: injection.context?.sessionType || null,
|
|
2292
|
+
files: injection.files,
|
|
2293
|
+
pointerInjected: injection.pointerInjected,
|
|
2294
|
+
fallbackFiles: injection.fallbackFiles,
|
|
2295
|
+
omittedFiles: injection.omittedFiles,
|
|
2296
|
+
truncated: injection.truncated,
|
|
2297
|
+
});
|
|
2298
|
+
return {
|
|
2299
|
+
appendSystemContext: injection.appendSystemContext,
|
|
2300
|
+
};
|
|
2301
|
+
} catch (error) {
|
|
2302
|
+
logger?.warn?.('[claworld:working-memory] unable to build prompt bootstrap context', error);
|
|
2303
|
+
}
|
|
2304
|
+
if (bootstrapTarget === CLAWORLD_BOOTSTRAP_TARGETS.MAIN) {
|
|
2305
|
+
return {
|
|
2306
|
+
appendSystemContext: buildClaworldContextPointer(),
|
|
2307
|
+
};
|
|
2308
|
+
}
|
|
2309
|
+
return;
|
|
2310
|
+
});
|
|
2311
|
+
|
|
1577
2312
|
api.on('before_tool_call', async (event, ctx) => {
|
|
1578
|
-
if (event?.toolName !== '
|
|
2313
|
+
if (event?.toolName !== 'claworld_manage_conversations') return;
|
|
2314
|
+
const params = event?.params && typeof event.params === 'object' && !Array.isArray(event.params)
|
|
2315
|
+
? event.params
|
|
2316
|
+
: {};
|
|
2317
|
+
if (normalizeTerminalConversationAction(params.action, null) !== 'request') return;
|
|
1579
2318
|
const requesterSessionKey = normalizeText(ctx?.sessionKey, null);
|
|
1580
2319
|
if (!requesterSessionKey) return;
|
|
1581
2320
|
return {
|
|
1582
2321
|
params: {
|
|
1583
|
-
...
|
|
2322
|
+
...params,
|
|
1584
2323
|
[INTERNAL_REQUESTER_SESSION_KEY_PARAM]: requesterSessionKey,
|
|
1585
2324
|
},
|
|
1586
2325
|
};
|
|
1587
2326
|
});
|
|
2327
|
+
|
|
2328
|
+
api.on('after_tool_call', async (event = {}, ctx = {}) => {
|
|
2329
|
+
if (!isSuccessfulHookToolCall(event)) return;
|
|
2330
|
+
const toolName = normalizeText(event?.toolName ?? ctx?.toolName, null);
|
|
2331
|
+
if (!toolName || !toolName.startsWith('claworld_')) return;
|
|
2332
|
+
const logger = getHookLogger(api);
|
|
2333
|
+
try {
|
|
2334
|
+
const workspaceRoot = await resolveHookWorkspaceRoot(api, event, ctx);
|
|
2335
|
+
if (!workspaceRoot) return;
|
|
2336
|
+
const maintenanceEvent = buildClaworldToolMaintenanceEvent({
|
|
2337
|
+
toolName,
|
|
2338
|
+
params: event?.params || {},
|
|
2339
|
+
result: hookToolResult(event),
|
|
2340
|
+
timestamp: event?.timestamp || ctx?.timestamp || null,
|
|
2341
|
+
});
|
|
2342
|
+
if (!maintenanceEvent) return;
|
|
2343
|
+
await appendClaworldJournalEvent(workspaceRoot, maintenanceEvent);
|
|
2344
|
+
} catch (error) {
|
|
2345
|
+
logger?.warn?.('[claworld:working-memory] unable to append tool event', error);
|
|
2346
|
+
}
|
|
2347
|
+
});
|
|
1588
2348
|
}
|
|
1589
2349
|
if (typeof api.registerHttpRoute === 'function') {
|
|
1590
2350
|
api.registerHttpRoute(buildClaworldStatusRoute(plugin));
|
|
1591
2351
|
}
|
|
1592
2352
|
if (typeof api.registerTool === 'function') {
|
|
1593
|
-
|
|
2353
|
+
const internalTools = new Map(
|
|
2354
|
+
buildRegisteredTools(api, plugin).map((tool) => [tool.name, tool]),
|
|
2355
|
+
);
|
|
2356
|
+
for (const tool of createTerminalToolAdapters(api, plugin, internalTools).map((terminalTool) => ({
|
|
2357
|
+
...terminalTool,
|
|
2358
|
+
execute: withToolErrorBoundary(terminalTool.name, terminalTool.execute),
|
|
2359
|
+
}))) {
|
|
1594
2360
|
api.registerTool(tool);
|
|
1595
2361
|
}
|
|
1596
2362
|
}
|