@xfxstudio/claworld 2026.6.9-testing.1 → 2026.6.10-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/README.md +2 -5
- package/openclaw.plugin.json +1 -1
- package/package.json +3 -6
- package/skills/claworld-main-session/SKILL.md +2 -0
- package/skills/claworld-management-session/SKILL.md +1 -0
- package/src/openclaw/plugin/conversation-viewer-env.js +56 -0
- package/src/openclaw/plugin/conversation-viewer.js +1117 -0
- package/src/openclaw/plugin/managed-config.js +192 -12
- package/src/openclaw/plugin/onboarding.js +2 -3
- package/src/openclaw/plugin/register-tooling.js +6 -3
- package/src/openclaw/plugin/register.js +69 -15
- package/src/openclaw/runtime/tool-contracts.js +40 -0
|
@@ -336,6 +336,25 @@ function inferExistingAgentId(config = {}, accountId = DEFAULT_CLAWORLD_ACCOUNT_
|
|
|
336
336
|
return DEFAULT_CLAWORLD_AGENT_ID;
|
|
337
337
|
}
|
|
338
338
|
|
|
339
|
+
const MANAGED_LEGACY_BUNDLED_SKILL_NAMES = Object.freeze([
|
|
340
|
+
'claworld-main-session',
|
|
341
|
+
'claworld-manage-worlds',
|
|
342
|
+
'claworld-help',
|
|
343
|
+
]);
|
|
344
|
+
|
|
345
|
+
function hasOnlyManagedBundledSkills(value) {
|
|
346
|
+
if (!Array.isArray(value) || value.length === 0) return false;
|
|
347
|
+
return value.every((skillName) => MANAGED_LEGACY_BUNDLED_SKILL_NAMES.includes(skillName));
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function buildManagedAgentEntry(options = {}) {
|
|
351
|
+
return {
|
|
352
|
+
id: options.agentId,
|
|
353
|
+
workspace: options.workspace,
|
|
354
|
+
...(options.agentDirExplicit && options.agentDir ? { agentDir: options.agentDir } : {}),
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
|
|
339
358
|
function buildManagedRoutingEntry(options = {}, existingRouting = {}) {
|
|
340
359
|
return {
|
|
341
360
|
...ensureObject(existingRouting),
|
|
@@ -488,6 +507,60 @@ export function resolveToolNames({ toolProfile = DEFAULT_CLAWORLD_TOOL_PROFILE }
|
|
|
488
507
|
return [...baseProfile];
|
|
489
508
|
}
|
|
490
509
|
|
|
510
|
+
const MANAGED_BUNDLED_SKILL_NAMES = Object.freeze([
|
|
511
|
+
'claworld-main-session',
|
|
512
|
+
'claworld-manage-worlds',
|
|
513
|
+
'claworld-help',
|
|
514
|
+
]);
|
|
515
|
+
|
|
516
|
+
export function resolveManagedAgentSkills({ toolProfile = DEFAULT_CLAWORLD_TOOL_PROFILE } = {}) {
|
|
517
|
+
const normalizedProfile = normalizeClaworldToolProfile(toolProfile);
|
|
518
|
+
return normalizedProfile === 'full' ? undefined : [...MANAGED_BUNDLED_SKILL_NAMES];
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
function describeToolAllowEntries(toolNames = []) {
|
|
522
|
+
if (toolNames.length === 1) {
|
|
523
|
+
return toolNames[0] === '*' ? '1 entry (includes *)' : '1 entry';
|
|
524
|
+
}
|
|
525
|
+
return toolNames.includes('*')
|
|
526
|
+
? `${toolNames.length} entries (includes *)`
|
|
527
|
+
: `${toolNames.length} entries`;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
export function buildWorkspaceAgentsContent({
|
|
531
|
+
agentId,
|
|
532
|
+
accountId,
|
|
533
|
+
registrationDisplayName,
|
|
534
|
+
appToken = null,
|
|
535
|
+
defaultTargetAgentId = null,
|
|
536
|
+
} = {}) {
|
|
537
|
+
const identityLine = appToken
|
|
538
|
+
? '- relay binding is resolved from the configured appToken at runtime'
|
|
539
|
+
: registrationDisplayName
|
|
540
|
+
? '- relay binding is created during runtime bootstrap and persists as backend-issued credentials'
|
|
541
|
+
: '- activation is pending until the user completes Claworld public identity setup';
|
|
542
|
+
|
|
543
|
+
return `# Claworld Channel Agent
|
|
544
|
+
|
|
545
|
+
This workspace is dedicated to the OpenClaw \`claworld\` channel.
|
|
546
|
+
|
|
547
|
+
Routing contract:
|
|
548
|
+
|
|
549
|
+
- local OpenClaw agent id: \`${agentId}\`
|
|
550
|
+
- claworld account id: \`${accountId}\`
|
|
551
|
+
${registrationDisplayName ? `- bootstrap display name: \`${registrationDisplayName}\`` : (appToken ? '- credential mode: appToken/manual binding' : '- credential mode: activation pending')}
|
|
552
|
+
${identityLine}
|
|
553
|
+
${defaultTargetAgentId ? `- default outbound target agentId: \`${defaultTargetAgentId}\`` : '- outbound sends require explicit target agentId inputs'}
|
|
554
|
+
|
|
555
|
+
Operating rules:
|
|
556
|
+
|
|
557
|
+
- keep this workspace focused on Claworld relay and world interactions
|
|
558
|
+
- use explicit \`claworld_*\` tools when they are available
|
|
559
|
+
- do not treat this workspace as the user's general-purpose main agent
|
|
560
|
+
- do not treat this as a separately bootstrapped OpenClaw persona
|
|
561
|
+
`;
|
|
562
|
+
}
|
|
563
|
+
|
|
491
564
|
function buildBoundAgentEntry(existingAgent = {}, agentId) {
|
|
492
565
|
const nextAgent = {
|
|
493
566
|
...ensureObject(existingAgent),
|
|
@@ -497,8 +570,41 @@ function buildBoundAgentEntry(existingAgent = {}, agentId) {
|
|
|
497
570
|
return nextAgent;
|
|
498
571
|
}
|
|
499
572
|
|
|
573
|
+
export function buildWorkspaceMemoryContent({
|
|
574
|
+
agentId,
|
|
575
|
+
accountId,
|
|
576
|
+
registrationDisplayName,
|
|
577
|
+
appToken = null,
|
|
578
|
+
defaultTargetAgentId = null,
|
|
579
|
+
} = {}) {
|
|
580
|
+
const identityLine = appToken
|
|
581
|
+
? '- relay binding: resolved from appToken at runtime'
|
|
582
|
+
: registrationDisplayName
|
|
583
|
+
? '- relay binding: assigned during runtime bootstrap'
|
|
584
|
+
: '- relay binding: pending until public identity setup completes';
|
|
585
|
+
|
|
586
|
+
return `# Claworld Memory
|
|
587
|
+
|
|
588
|
+
- workspace owner: \`${agentId}\`
|
|
589
|
+
- claworld account: \`${accountId}\`
|
|
590
|
+
${registrationDisplayName ? `- bootstrap display name: \`${registrationDisplayName}\`` : ''}
|
|
591
|
+
${identityLine}
|
|
592
|
+
${defaultTargetAgentId ? `- default outbound target agentId: \`${defaultTargetAgentId}\`` : ''}
|
|
593
|
+
|
|
594
|
+
Use this file for durable Claworld-specific notes only.
|
|
595
|
+
|
|
596
|
+
- keep world rules, pairing context, and recurring counterpart preferences here when they help future Claworld conversations
|
|
597
|
+
- do not duplicate a full standalone OpenClaw bootstrap/persona here
|
|
598
|
+
- prefer channel/world-specific memory over general-purpose assistant memory
|
|
599
|
+
`;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
export function resolveDefaultManagedWorkspace(agentId = DEFAULT_CLAWORLD_AGENT_ID) {
|
|
603
|
+
return `~/.openclaw/workspace-${agentId}`;
|
|
604
|
+
}
|
|
605
|
+
|
|
500
606
|
export function resolveDefaultManagedDisplayName(accountId = DEFAULT_CLAWORLD_ACCOUNT_ID) {
|
|
501
|
-
return `${titleCase(accountId)} Channel`;
|
|
607
|
+
return `${titleCase(accountId)} Channel Agent`;
|
|
502
608
|
}
|
|
503
609
|
|
|
504
610
|
export function resolveClaworldManagedRuntimeOptions({
|
|
@@ -509,6 +615,7 @@ export function resolveClaworldManagedRuntimeOptions({
|
|
|
509
615
|
installerState = null,
|
|
510
616
|
} = {}) {
|
|
511
617
|
const resolvedAccountId = normalizeText(accountId, DEFAULT_CLAWORLD_ACCOUNT_ID);
|
|
618
|
+
const attachToExistingAgent = overrides.attachToExistingAgent !== false;
|
|
512
619
|
const existingBackup = findClaworldManagedRuntimeBackup(installerState, resolvedAccountId);
|
|
513
620
|
const inferredAgentId = inferExistingAgentId(cfg, resolvedAccountId)
|
|
514
621
|
|| normalizeText(existingBackup.agentId, null);
|
|
@@ -516,7 +623,20 @@ export function resolveClaworldManagedRuntimeOptions({
|
|
|
516
623
|
const existingAgent = findAgentEntry(cfg, agentId);
|
|
517
624
|
const existingAccount = findManagedAccountEntry(cfg, resolvedAccountId);
|
|
518
625
|
const replaceManagedRuntime = overrides.replaceManagedRuntime !== false;
|
|
519
|
-
const
|
|
626
|
+
const explicitWorkspace = normalizeText(overrides.workspace, null);
|
|
627
|
+
const manageAgentEntry = overrides.manageAgentEntry === true
|
|
628
|
+
|| overrides.agentDirExplicit === true
|
|
629
|
+
|| attachToExistingAgent !== true;
|
|
630
|
+
const manageWorkspace = overrides.manageWorkspace === true
|
|
631
|
+
|| Boolean(explicitWorkspace)
|
|
632
|
+
|| attachToExistingAgent !== true;
|
|
633
|
+
const defaultWorkspace = manageWorkspace ? resolveDefaultManagedWorkspace(agentId) : null;
|
|
634
|
+
const workspace = normalizeText(
|
|
635
|
+
explicitWorkspace,
|
|
636
|
+
replaceManagedRuntime
|
|
637
|
+
? normalizeText(existingAgent?.workspace, normalizeText(existingBackup.workspace, defaultWorkspace))
|
|
638
|
+
: normalizeText(existingAgent?.workspace, normalizeText(existingBackup.workspace, defaultWorkspace)),
|
|
639
|
+
);
|
|
520
640
|
const serverUrl = normalizeText(
|
|
521
641
|
overrides.serverUrl,
|
|
522
642
|
normalizeText(input.httpUrl, normalizeText(input.url, normalizeText(existingBackup.serverUrl, DEFAULT_CLAWORLD_SERVER_URL))),
|
|
@@ -560,9 +680,14 @@ export function resolveClaworldManagedRuntimeOptions({
|
|
|
560
680
|
|
|
561
681
|
return {
|
|
562
682
|
repoRoot: normalizeText(overrides.repoRoot, null),
|
|
683
|
+
attachToExistingAgent,
|
|
563
684
|
agentId,
|
|
564
685
|
accountId: resolvedAccountId,
|
|
565
686
|
workspace,
|
|
687
|
+
manageAgentEntry,
|
|
688
|
+
manageWorkspace,
|
|
689
|
+
agentDir: normalizeText(overrides.agentDir, null),
|
|
690
|
+
agentDirExplicit: overrides.agentDirExplicit === true,
|
|
566
691
|
serverUrl,
|
|
567
692
|
apiKey,
|
|
568
693
|
appToken,
|
|
@@ -590,6 +715,7 @@ export function applyClaworldManagedRuntimeConfig(inputConfig = {}, options = {}
|
|
|
590
715
|
const replaceManagedRuntime = options.replaceManagedRuntime !== false;
|
|
591
716
|
const preserveDefaultAccount = options.preserveDefaultAccount === true;
|
|
592
717
|
const sessionDmScope = normalizeText(options.sessionDmScope, DEFAULT_CLAWORLD_DM_SCOPE);
|
|
718
|
+
const manageAgentEntry = options.manageAgentEntry === true;
|
|
593
719
|
|
|
594
720
|
const removedManagedToolNames = new Set(CLAWORLD_PUBLIC_TOOL_NAMES);
|
|
595
721
|
if (inputConfig?.tools && typeof inputConfig.tools === 'object') {
|
|
@@ -628,18 +754,72 @@ export function applyClaworldManagedRuntimeConfig(inputConfig = {}, options = {}
|
|
|
628
754
|
|
|
629
755
|
config.agents = ensureObject(config.agents);
|
|
630
756
|
const existingAgentList = Array.isArray(config.agents.list) ? [...config.agents.list] : [];
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
757
|
+
if (manageAgentEntry) {
|
|
758
|
+
const managedAgentEntry = buildManagedAgentEntry(options);
|
|
759
|
+
if (replaceManagedRuntime) {
|
|
760
|
+
const removedAgentEntries = existingAgentList.filter((item) => ensureObject(item).id === options.agentId).length;
|
|
761
|
+
config.agents.list = [
|
|
762
|
+
...existingAgentList.filter((item) => ensureObject(item).id !== options.agentId),
|
|
763
|
+
{
|
|
764
|
+
...managedAgentEntry,
|
|
765
|
+
tools: mergeManagedPluginToolExposure(managedAgentEntry.tools),
|
|
766
|
+
},
|
|
767
|
+
];
|
|
768
|
+
summary.push(
|
|
769
|
+
removedAgentEntries > 0
|
|
770
|
+
? `replaced managed agent entry ${options.agentId}`
|
|
771
|
+
: `added workspace-scoped agent entry ${options.agentId}`,
|
|
772
|
+
);
|
|
773
|
+
} else {
|
|
774
|
+
const agentIndex = findAgentIndex(existingAgentList, options.agentId);
|
|
775
|
+
if (agentIndex >= 0) {
|
|
776
|
+
const existingAgent = ensureObject(existingAgentList[agentIndex]);
|
|
777
|
+
const existingAgentDir = normalizeText(existingAgent.agentDir, null);
|
|
778
|
+
const keepExistingAgentDir = Boolean(
|
|
779
|
+
existingAgentDir
|
|
780
|
+
&& (
|
|
781
|
+
options.agentDirExplicit
|
|
782
|
+
|| existingAgentDir !== normalizeText(options.agentDir, null)
|
|
783
|
+
),
|
|
784
|
+
);
|
|
785
|
+
const nextAgentEntry = {
|
|
786
|
+
...existingAgent,
|
|
787
|
+
id: options.agentId,
|
|
788
|
+
workspace: normalizeText(existingAgent.workspace, options.workspace),
|
|
789
|
+
...(keepExistingAgentDir ? { agentDir: existingAgentDir } : {}),
|
|
790
|
+
};
|
|
791
|
+
if (!keepExistingAgentDir) {
|
|
792
|
+
delete nextAgentEntry.agentDir;
|
|
793
|
+
}
|
|
794
|
+
if (hasOnlyManagedBundledSkills(existingAgent.skills)) {
|
|
795
|
+
delete nextAgentEntry.skills;
|
|
796
|
+
}
|
|
797
|
+
nextAgentEntry.tools = mergeManagedPluginToolExposure(existingAgent.tools);
|
|
798
|
+
existingAgentList[agentIndex] = nextAgentEntry;
|
|
799
|
+
summary.push(`updated existing agent entry ${options.agentId}`);
|
|
800
|
+
} else {
|
|
801
|
+
existingAgentList.push({
|
|
802
|
+
...managedAgentEntry,
|
|
803
|
+
tools: mergeManagedPluginToolExposure(managedAgentEntry.tools),
|
|
804
|
+
});
|
|
805
|
+
summary.push(`added workspace-scoped agent entry ${options.agentId}`);
|
|
806
|
+
}
|
|
807
|
+
config.agents.list = existingAgentList;
|
|
808
|
+
}
|
|
637
809
|
} else {
|
|
638
|
-
existingAgentList
|
|
639
|
-
|
|
640
|
-
|
|
810
|
+
const agentIndex = findAgentIndex(existingAgentList, options.agentId);
|
|
811
|
+
if (agentIndex >= 0) {
|
|
812
|
+
const existingAgent = ensureObject(existingAgentList[agentIndex]);
|
|
813
|
+
existingAgentList[agentIndex] = buildBoundAgentEntry(existingAgent, options.agentId);
|
|
814
|
+
config.agents.list = existingAgentList;
|
|
815
|
+
summary.push(`updated bound agent tool exposure ${options.agentId}`);
|
|
816
|
+
} else {
|
|
817
|
+
existingAgentList.push(buildBoundAgentEntry({}, options.agentId));
|
|
818
|
+
config.agents.list = existingAgentList;
|
|
819
|
+
summary.push(`added bound agent entry ${options.agentId}`);
|
|
820
|
+
}
|
|
821
|
+
summary.push(`attached claworld account ${options.accountId} to existing local agent ${options.agentId}`);
|
|
641
822
|
}
|
|
642
|
-
summary.push(`attached claworld account ${options.accountId} to local agent ${options.agentId}`);
|
|
643
823
|
|
|
644
824
|
config.channels = ensureObject(config.channels);
|
|
645
825
|
const existingClaworldRoot = ensureObject(config.channels.claworld);
|
|
@@ -133,6 +133,7 @@ export function inspectManagedClaworldInstall({
|
|
|
133
133
|
const setupReady = Boolean(
|
|
134
134
|
managedAccountPresent
|
|
135
135
|
&& managedBindingPresent
|
|
136
|
+
&& (managedOptions.manageAgentEntry !== true || managedAgentPresent)
|
|
136
137
|
);
|
|
137
138
|
|
|
138
139
|
let statusLabel = 'needs setup';
|
|
@@ -247,9 +248,7 @@ async function applyManagedOnboardingConfig({
|
|
|
247
248
|
managedOptions.appToken
|
|
248
249
|
? 'Activation state: ready via configured appToken'
|
|
249
250
|
: 'Activation state: pending until claworld_manage_account(action=activate_account) runs',
|
|
250
|
-
'
|
|
251
|
-
'This flow refreshes plugin-side config and binds claworld onto the selected local agent.',
|
|
252
|
-
'Setup lifecycle: OpenClaw host-native setup.',
|
|
251
|
+
'This flow refreshes plugin-side config and binds claworld onto the selected local agent. It does not run installer commands or start a backend service.',
|
|
253
252
|
];
|
|
254
253
|
await prompter.note(
|
|
255
254
|
noteLines.join('\n'),
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
} from '../runtime/backend-error-context.js';
|
|
21
21
|
|
|
22
22
|
export const INTERNAL_REQUESTER_SESSION_KEY_PARAM = '__claworldRequesterSessionKey';
|
|
23
|
+
export const INTERNAL_WORKSPACE_ROOT_PARAM = '__claworldWorkspaceRoot';
|
|
23
24
|
|
|
24
25
|
export function normalizeText(value, fallback = null) {
|
|
25
26
|
if (value == null) return fallback;
|
|
@@ -240,9 +241,10 @@ export async function resolveToolContext(
|
|
|
240
241
|
runtime: api?.runtime || null,
|
|
241
242
|
accountId,
|
|
242
243
|
runtimeConfig,
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
244
|
+
agentId: normalizeText(params.agentId, runtimeConfig.relay?.agentId || null),
|
|
245
|
+
requesterSessionKey: normalizeText(params[INTERNAL_REQUESTER_SESSION_KEY_PARAM], null),
|
|
246
|
+
workspaceRoot: normalizeText(params[INTERNAL_WORKSPACE_ROOT_PARAM], null),
|
|
247
|
+
});
|
|
246
248
|
if (
|
|
247
249
|
requiredPublicIdentityCapability
|
|
248
250
|
&& (
|
|
@@ -282,6 +284,7 @@ export async function resolveToolContext(
|
|
|
282
284
|
runtimeConfig,
|
|
283
285
|
agentId,
|
|
284
286
|
requesterSessionKey: normalizeText(params[INTERNAL_REQUESTER_SESSION_KEY_PARAM], null),
|
|
287
|
+
workspaceRoot: normalizeText(params[INTERNAL_WORKSPACE_ROOT_PARAM], null),
|
|
285
288
|
};
|
|
286
289
|
}
|
|
287
290
|
|
|
@@ -2,6 +2,10 @@ import {
|
|
|
2
2
|
createClaworldChannelPlugin,
|
|
3
3
|
recordClaworldRuntimeAssistantOutput,
|
|
4
4
|
} from './claworld-channel-plugin.js';
|
|
5
|
+
import {
|
|
6
|
+
attachConversationViewerToPayload,
|
|
7
|
+
buildConversationViewerRoute,
|
|
8
|
+
} from './conversation-viewer.js';
|
|
5
9
|
import {
|
|
6
10
|
projectToolChatRequestMutationResponse,
|
|
7
11
|
projectToolCreateWorldResponse,
|
|
@@ -41,6 +45,7 @@ import {
|
|
|
41
45
|
inferChatInboxAction,
|
|
42
46
|
inferManageWorldAction,
|
|
43
47
|
INTERNAL_REQUESTER_SESSION_KEY_PARAM,
|
|
48
|
+
INTERNAL_WORKSPACE_ROOT_PARAM,
|
|
44
49
|
integerParam,
|
|
45
50
|
loadCurrentConfig,
|
|
46
51
|
MANAGE_WORLD_ACTIONS,
|
|
@@ -267,6 +272,24 @@ function buildTerminalActionResult({ tool, action, payload = {}, status = null }
|
|
|
267
272
|
});
|
|
268
273
|
}
|
|
269
274
|
|
|
275
|
+
async function attachLocalConversationViewer(payload, {
|
|
276
|
+
context = {},
|
|
277
|
+
params = {},
|
|
278
|
+
role = null,
|
|
279
|
+
source = null,
|
|
280
|
+
logger = console,
|
|
281
|
+
} = {}) {
|
|
282
|
+
return await attachConversationViewerToPayload(payload, {
|
|
283
|
+
accountId: context.accountId || null,
|
|
284
|
+
viewerAgentId: context.agentId || null,
|
|
285
|
+
role,
|
|
286
|
+
source,
|
|
287
|
+
cfg: context.cfg || {},
|
|
288
|
+
workspaceRoot: context.workspaceRoot || params[INTERNAL_WORKSPACE_ROOT_PARAM] || null,
|
|
289
|
+
logger,
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
|
|
270
293
|
function normalizeChatInboxListFiltersInput(params = {}) {
|
|
271
294
|
const source = normalizeObject(params.filters, {}) || {};
|
|
272
295
|
const normalized = {
|
|
@@ -1093,10 +1116,17 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
|
|
|
1093
1116
|
conversationKey,
|
|
1094
1117
|
localSessionKey,
|
|
1095
1118
|
});
|
|
1119
|
+
const payloadWithViewer = await attachLocalConversationViewer(payload, {
|
|
1120
|
+
context,
|
|
1121
|
+
params,
|
|
1122
|
+
role: 'participant',
|
|
1123
|
+
source: 'close_conversation',
|
|
1124
|
+
logger: getHookLogger(api),
|
|
1125
|
+
});
|
|
1096
1126
|
return buildTerminalActionResult({
|
|
1097
1127
|
tool: manageConversationsTool,
|
|
1098
1128
|
action,
|
|
1099
|
-
payload,
|
|
1129
|
+
payload: payloadWithViewer,
|
|
1100
1130
|
});
|
|
1101
1131
|
}
|
|
1102
1132
|
requireManageWorldField('action', `action must be one of ${TERMINAL_CONVERSATION_ACTIONS.join(', ')}`);
|
|
@@ -1691,6 +1721,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
1691
1721
|
'Do not use this tool for replying inside an already-open Claworld chat or for runtime live turns.',
|
|
1692
1722
|
'After creation, use claworld_chat_inbox to inspect pending, expired, rejected, opening, ending, active, silent, or ended status, or wait for the peer to accept.',
|
|
1693
1723
|
'Once accepted, the runtime owns the live conversation loop.',
|
|
1724
|
+
'If the result includes conversationViewer.url, include that local viewer link in the owner-facing response so the human can watch the chat live.',
|
|
1694
1725
|
],
|
|
1695
1726
|
examples: [
|
|
1696
1727
|
{
|
|
@@ -1759,7 +1790,14 @@ function buildRegisteredTools(api, plugin) {
|
|
|
1759
1790
|
openingMessage: params.openingMessage || null,
|
|
1760
1791
|
worldId: params.worldId || null,
|
|
1761
1792
|
});
|
|
1762
|
-
|
|
1793
|
+
const payloadWithViewer = await attachLocalConversationViewer(payload, {
|
|
1794
|
+
context,
|
|
1795
|
+
params,
|
|
1796
|
+
role: 'requester',
|
|
1797
|
+
source: 'request_chat',
|
|
1798
|
+
logger: getHookLogger(api),
|
|
1799
|
+
});
|
|
1800
|
+
return buildToolResult(projectToolChatRequestMutationResponse(payloadWithViewer, { accountId: context.accountId }));
|
|
1763
1801
|
},
|
|
1764
1802
|
},
|
|
1765
1803
|
{
|
|
@@ -1778,6 +1816,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
1778
1816
|
'For user requests to contact, PK, continue, or re-engage a Claworld peer, use claworld_manage_conversations(action=request) with the intended direct or world scope.',
|
|
1779
1817
|
'Peer-facing opener/reply/final content is delivered by the Conversation Session and backend conversation runtime. Main Session must not use sessions_send to write peer-facing content into a local conversation session.',
|
|
1780
1818
|
'Prefer Claworld conversation state, reports, and concise summaries before inspecting raw local transcript details.',
|
|
1819
|
+
'If an accept result includes conversationViewer.url, include that local viewer link in the owner-facing response or report.',
|
|
1781
1820
|
'Global counts stay visible even when filters are applied; filtered counts describe the current narrowed result set.',
|
|
1782
1821
|
'After action=accept or action=reject, call action=list again to refresh the inbox view.',
|
|
1783
1822
|
],
|
|
@@ -1868,7 +1907,16 @@ function buildRegisteredTools(api, plugin) {
|
|
|
1868
1907
|
...context,
|
|
1869
1908
|
chatRequestId,
|
|
1870
1909
|
});
|
|
1871
|
-
|
|
1910
|
+
const payloadWithViewer = action === 'accept'
|
|
1911
|
+
? await attachLocalConversationViewer(payload, {
|
|
1912
|
+
context,
|
|
1913
|
+
params,
|
|
1914
|
+
role: 'recipient',
|
|
1915
|
+
source: 'accept_chat_request',
|
|
1916
|
+
logger: getHookLogger(api),
|
|
1917
|
+
})
|
|
1918
|
+
: payload;
|
|
1919
|
+
return buildToolResult(projectToolChatInboxActionResponse(payloadWithViewer, {
|
|
1872
1920
|
accountId: context.accountId,
|
|
1873
1921
|
action,
|
|
1874
1922
|
}));
|
|
@@ -2148,7 +2196,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
2148
2196
|
}));
|
|
2149
2197
|
}
|
|
2150
2198
|
|
|
2151
|
-
export function registerClaworldPluginFull(api, plugin) {
|
|
2199
|
+
export function registerClaworldPluginFull(api, plugin, { fetchImpl = globalThis.fetch } = {}) {
|
|
2152
2200
|
if (!plugin) {
|
|
2153
2201
|
throw new Error('registerClaworldPluginFull requires a plugin instance');
|
|
2154
2202
|
}
|
|
@@ -2217,17 +2265,16 @@ export function registerClaworldPluginFull(api, plugin) {
|
|
|
2217
2265
|
? event.params
|
|
2218
2266
|
: {};
|
|
2219
2267
|
const requesterSessionKey = normalizeText(ctx?.sessionKey, null);
|
|
2220
|
-
if (
|
|
2221
|
-
toolName !== 'claworld_manage_conversations'
|
|
2222
|
-
|| normalizeTerminalConversationAction(params.action, null) !== 'request'
|
|
2223
|
-
|| !requesterSessionKey
|
|
2224
|
-
) {
|
|
2225
|
-
return;
|
|
2226
|
-
}
|
|
2268
|
+
if (toolName !== 'claworld_manage_conversations') return;
|
|
2227
2269
|
const logger = getHookLogger(api);
|
|
2270
|
+
let workspaceRoot = null;
|
|
2228
2271
|
try {
|
|
2229
|
-
|
|
2230
|
-
if (
|
|
2272
|
+
workspaceRoot = await resolveHookWorkspaceRoot(api, event, ctx);
|
|
2273
|
+
if (
|
|
2274
|
+
workspaceRoot
|
|
2275
|
+
&& requesterSessionKey
|
|
2276
|
+
&& normalizeTerminalConversationAction(params.action, null) === 'request'
|
|
2277
|
+
) {
|
|
2231
2278
|
await updateClaworldSessionDirectory(
|
|
2232
2279
|
workspaceRoot,
|
|
2233
2280
|
{
|
|
@@ -2248,10 +2295,12 @@ export function registerClaworldPluginFull(api, plugin) {
|
|
|
2248
2295
|
} catch (error) {
|
|
2249
2296
|
logger?.warn?.('[claworld:working-memory] unable to update requester session directory', error);
|
|
2250
2297
|
}
|
|
2298
|
+
if (!requesterSessionKey && !workspaceRoot) return;
|
|
2251
2299
|
return {
|
|
2252
2300
|
params: {
|
|
2253
2301
|
...params,
|
|
2254
|
-
[INTERNAL_REQUESTER_SESSION_KEY_PARAM]: requesterSessionKey,
|
|
2302
|
+
...(requesterSessionKey ? { [INTERNAL_REQUESTER_SESSION_KEY_PARAM]: requesterSessionKey } : {}),
|
|
2303
|
+
...(workspaceRoot ? { [INTERNAL_WORKSPACE_ROOT_PARAM]: workspaceRoot } : {}),
|
|
2255
2304
|
},
|
|
2256
2305
|
};
|
|
2257
2306
|
});
|
|
@@ -2280,6 +2329,11 @@ export function registerClaworldPluginFull(api, plugin) {
|
|
|
2280
2329
|
}
|
|
2281
2330
|
if (typeof api.registerHttpRoute === 'function') {
|
|
2282
2331
|
api.registerHttpRoute(buildClaworldStatusRoute(plugin));
|
|
2332
|
+
api.registerHttpRoute(buildConversationViewerRoute(plugin, {
|
|
2333
|
+
api,
|
|
2334
|
+
fetchImpl,
|
|
2335
|
+
logger: getHookLogger(api),
|
|
2336
|
+
}));
|
|
2283
2337
|
}
|
|
2284
2338
|
if (typeof api.registerTool === 'function') {
|
|
2285
2339
|
const internalTools = new Map(
|
|
@@ -2310,7 +2364,7 @@ export function registerClaworldPlugin(api, options = {}) {
|
|
|
2310
2364
|
} = options;
|
|
2311
2365
|
const plugin = existingPlugin || createClaworldChannelPlugin(pluginOptions);
|
|
2312
2366
|
api.registerChannel({ plugin });
|
|
2313
|
-
registerClaworldPluginFull(api, plugin);
|
|
2367
|
+
registerClaworldPluginFull(api, plugin, pluginOptions);
|
|
2314
2368
|
return plugin;
|
|
2315
2369
|
}
|
|
2316
2370
|
|
|
@@ -641,6 +641,35 @@ function projectChatRequestOrigin(origin = {}) {
|
|
|
641
641
|
};
|
|
642
642
|
}
|
|
643
643
|
|
|
644
|
+
function projectConversationViewer(viewer = null) {
|
|
645
|
+
if (!viewer || typeof viewer !== 'object' || Array.isArray(viewer)) return null;
|
|
646
|
+
const id = normalizeText(viewer.id, normalizeText(viewer.viewerId, null));
|
|
647
|
+
const url = normalizeText(viewer.url, null);
|
|
648
|
+
if (!id && !url && normalizeText(viewer.status, null) !== 'unavailable') return null;
|
|
649
|
+
return {
|
|
650
|
+
id,
|
|
651
|
+
status: normalizeText(viewer.status, 'ready'),
|
|
652
|
+
url,
|
|
653
|
+
localFile: normalizeText(viewer.localFile, null),
|
|
654
|
+
fileUrl: normalizeText(viewer.fileUrl, null),
|
|
655
|
+
chatRequestId: normalizeText(viewer.chatRequestId, null),
|
|
656
|
+
conversationKey: normalizeText(viewer.conversationKey, null),
|
|
657
|
+
localSessionKey: normalizeText(viewer.localSessionKey, null),
|
|
658
|
+
replay: viewer.replay && typeof viewer.replay === 'object' && !Array.isArray(viewer.replay)
|
|
659
|
+
? {
|
|
660
|
+
firstOpenReplaysEndedConversation: typeof viewer.replay.firstOpenReplaysEndedConversation === 'boolean'
|
|
661
|
+
? viewer.replay.firstOpenReplaysEndedConversation
|
|
662
|
+
: null,
|
|
663
|
+
secondOpenShowsFullTranscript: typeof viewer.replay.secondOpenShowsFullTranscript === 'boolean'
|
|
664
|
+
? viewer.replay.secondOpenShowsFullTranscript
|
|
665
|
+
: null,
|
|
666
|
+
}
|
|
667
|
+
: null,
|
|
668
|
+
note: normalizeText(viewer.note, null),
|
|
669
|
+
reason: normalizeText(viewer.reason, null),
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
|
|
644
673
|
function projectChatRequestItem(request = {}) {
|
|
645
674
|
if (!request || typeof request !== 'object') return null;
|
|
646
675
|
const requestContext = request.requestContext && typeof request.requestContext === 'object' && !Array.isArray(request.requestContext)
|
|
@@ -656,6 +685,7 @@ function projectChatRequestItem(request = {}) {
|
|
|
656
685
|
? request.conversation
|
|
657
686
|
: requestContext.conversation,
|
|
658
687
|
);
|
|
688
|
+
const conversationViewer = projectConversationViewer(request.conversationViewer);
|
|
659
689
|
return {
|
|
660
690
|
chatRequestId: normalizeText(request.chatRequestId || request.requestId, null),
|
|
661
691
|
status: normalizeText(request.status, 'pending'),
|
|
@@ -681,11 +711,13 @@ function projectChatRequestItem(request = {}) {
|
|
|
681
711
|
toAgent: projectToolAgentSummary(request.toAgent),
|
|
682
712
|
counterparty: projectToolAgentSummary(request.counterparty),
|
|
683
713
|
conversation,
|
|
714
|
+
...(conversationViewer ? { conversationViewer } : {}),
|
|
684
715
|
};
|
|
685
716
|
}
|
|
686
717
|
|
|
687
718
|
function projectChatInboxChatItem(chat = {}) {
|
|
688
719
|
if (!chat || typeof chat !== 'object' || Array.isArray(chat)) return null;
|
|
720
|
+
const conversationViewer = projectConversationViewer(chat.conversationViewer);
|
|
689
721
|
return {
|
|
690
722
|
chatRequestId: normalizeText(chat.chatRequestId, null),
|
|
691
723
|
status: normalizeText(chat.status, null),
|
|
@@ -699,6 +731,7 @@ function projectChatInboxChatItem(chat = {}) {
|
|
|
699
731
|
counterparty: projectToolAgentSummary(chat.counterparty),
|
|
700
732
|
conversation: normalizeConversationScopeDetails(chat.conversation),
|
|
701
733
|
feedbackSummary: projectConversationFeedbackSummary(chat.feedbackSummary),
|
|
734
|
+
...(conversationViewer ? { conversationViewer } : {}),
|
|
702
735
|
};
|
|
703
736
|
}
|
|
704
737
|
|
|
@@ -764,12 +797,19 @@ export function projectToolChatRequestMutationResponse(result = {}, { accountId
|
|
|
764
797
|
const projectedRequest = projectChatRequestItem(request);
|
|
765
798
|
const kickoff = projectChatRequestKickoff(result.kickoff || result.request?.kickoff);
|
|
766
799
|
const projectedChat = projectChatInboxChatItem(result.chat);
|
|
800
|
+
const conversationViewer = projectConversationViewer(
|
|
801
|
+
result.conversationViewer
|
|
802
|
+
|| request?.conversationViewer
|
|
803
|
+
|| result.request?.conversationViewer
|
|
804
|
+
|| result.chat?.conversationViewer,
|
|
805
|
+
);
|
|
767
806
|
const normalizedStatus = normalizeText(result.status, projectedRequest?.status || 'pending');
|
|
768
807
|
return {
|
|
769
808
|
status: normalizedStatus,
|
|
770
809
|
accountId: normalizeText(accountId, null),
|
|
771
810
|
chatRequest: projectedRequest,
|
|
772
811
|
...(projectedChat ? { chat: projectedChat } : {}),
|
|
812
|
+
...(conversationViewer ? { conversationViewer } : {}),
|
|
773
813
|
kickoff,
|
|
774
814
|
nextAction: normalizeText(
|
|
775
815
|
result.nextAction,
|