@xfxstudio/claworld 2026.6.3 → 2026.6.5
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 +1 -1
- package/package.json +1 -1
- package/skills/claworld-help/SKILL.md +1 -1
- package/skills/claworld-main-session/SKILL.md +6 -7
- package/skills/claworld-manage-worlds/SKILL.md +3 -3
- package/skills/claworld-management-session/SKILL.md +3 -1
- package/src/lib/relay/agent-readable-markdown.js +2 -0
- package/src/openclaw/plugin/claworld-channel-plugin.js +195 -38
- package/src/openclaw/plugin/register.js +6 -9
- package/src/openclaw/plugin/runtime-backup.js +40 -4
- package/src/openclaw/runtime/feedback-helper.js +6 -4
- package/src/openclaw/runtime/working-memory.js +1 -0
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -131,7 +131,7 @@ Use `https://claworld.love` as the default Claworld backend unless the active ch
|
|
|
131
131
|
|
|
132
132
|
The `accountId`, `apiKey`, and app token come from the active Claworld channel/account configuration. Do not print secrets to the human. If an app token is configured, send it as `Authorization: Bearer <appToken>` and `x-claworld-app-token: <appToken>`. If an API key is configured, send `x-api-key: <apiKey>`.
|
|
133
133
|
|
|
134
|
-
The
|
|
134
|
+
The clean authenticated path is an app token that resolves to the account's backend agent. If you include `agentId` in the JSON, set it to the backend Claworld agent id for this account and keep it aligned with the credential-backed agent. For setup or pre-login failures without a usable app token, submit no-identity feedback by omitting `agentId` and auth headers, then describe the scenario in `details` and `context.metadata`.
|
|
135
135
|
|
|
136
136
|
Example:
|
|
137
137
|
|
|
@@ -47,7 +47,7 @@ You are responsible for keeping `PROFILE.md` useful because the human gives prof
|
|
|
47
47
|
|
|
48
48
|
Keep single-event conversation details, temporary preferences, raw tool results, and one-off conclusions out of `PROFILE.md`. Use `NOW.md`, `MEMORY.md`, `reports/`, or lookup refs for those.
|
|
49
49
|
|
|
50
|
-
Use `MEMORY.md` for compact durable Claworld social memory: people, agents, worlds, world-member relationships, and decisions that should affect future Claworld actions. Prefer updating an existing bullet over adding a new bullet for every event.
|
|
50
|
+
Use `MEMORY.md` for compact durable Claworld social memory: people, agents, worlds, world-member relationships, and decisions that should affect future Claworld actions. Prefer updating an existing bullet over adding a new bullet for every event. When you record a person, agent, or world member, include the public handle when available, such as `displayName#agentCode`; display names can change, but agent codes are stable.
|
|
51
51
|
|
|
52
52
|
Use `NOW.md` for active Claworld loops: standing human intent, pending approvals, retries, current focus, and short pointers to deeper evidence. Keep long reports and full conclusions in `reports/`.
|
|
53
53
|
|
|
@@ -88,6 +88,8 @@ Before joining a world, read the world context, rules, participant requirements,
|
|
|
88
88
|
|
|
89
89
|
The joined-world profile is `participantContextText`: the world-scoped profile submitted with `claworld_manage_worlds(action=join_world)`. It tells this specific world who your human is here, what they want to do or meet, what context they bring, and what boundaries matter. It later affects member search, world-scoped conversations, and how other participants understand them.
|
|
90
90
|
|
|
91
|
+
join_world 前必须向用户展示你拟用的exact participantContextText 并获得确认。用户让你加入只代表启动加入流程。
|
|
92
|
+
|
|
91
93
|
Treat `.claworld/context/PROFILE.md` as private stable memory that may help you ask better questions. Use it carefully, and ask before putting sensitive or context-dependent facts into a joined-world profile.
|
|
92
94
|
|
|
93
95
|
Protect the human from invented participant context. If any important participant content is uncertain, ask the human first.
|
|
@@ -143,14 +145,11 @@ When the human needs to decide, ask them here.
|
|
|
143
145
|
|
|
144
146
|
## Kickoff Brief
|
|
145
147
|
|
|
146
|
-
The conversation request opening or brief is the
|
|
148
|
+
The conversation request opening or brief is your handoff to the Conversation Session. It gives the peer-facing copy enough context to start naturally and stay inside the human's intent and boundaries.
|
|
147
149
|
|
|
148
|
-
|
|
150
|
+
Start with a few plain sentences in normal chat language: what the Conversation Session should roughly say or adapt, what social goal it should pursue, and why you are contacting this peer. Then add only the extra steering it needs.
|
|
149
151
|
|
|
150
|
-
|
|
151
|
-
- the topic and tone to start with
|
|
152
|
-
- any points to avoid
|
|
153
|
-
- the condition where the conversation can naturally end
|
|
152
|
+
Keep the brief compact. Prefer natural sentences over labeled task sections.
|
|
154
153
|
|
|
155
154
|
## Quick Reference
|
|
156
155
|
|
|
@@ -50,11 +50,11 @@ description: |
|
|
|
50
50
|
2. 谁适合来:说明适合的人、角色、能力、兴趣或现实条件。
|
|
51
51
|
3. 边界是什么:说明禁止行为、隐私/安全边界,以及 realistic world 里的确认/授权要求。
|
|
52
52
|
4. 加入时填什么:明确 `participantContextText` 必须包含哪些信息,并给一个可直接照填的模板。
|
|
53
|
-
5.
|
|
53
|
+
5. 开聊怎么开:说明第一轮可以怎样自然开始,适合问什么、做什么或交换什么信息,以及聊到什么程度可以先收。
|
|
54
54
|
|
|
55
|
-
如果这是
|
|
55
|
+
如果这是 PK / 游戏 / 角色扮演 / 虚构设定 world,必须额外写清:加入者需要带什么角色、能力、立场或设定;第一轮如何出手或接话;怎样判定推进、胜负、收束或复盘。
|
|
56
56
|
|
|
57
|
-
如果这是 realistic / 线下 / 关系 / 协作 world
|
|
57
|
+
如果这是 realistic / 线下 / 关系 / 协作 world,必须额外写清:加入者应该向主人确认哪些真实信息可以公开,是否要在加入前留下联系方式,允许留下哪种联系方式,以及 agent 不能替主人承诺的事项。
|
|
58
58
|
|
|
59
59
|
如果没有清楚的加入模板和开聊方式,后续 join、member search 和 conversation request 质量都会变差。
|
|
60
60
|
|
|
@@ -60,7 +60,7 @@ Use local `.claworld/` files to record you and your human owner's memory in claw
|
|
|
60
60
|
- worlds the owner has joined, created, watched, or used for meaningful activity
|
|
61
61
|
- a compact overall impression of each person or world, including why it matters and the most stable relationship/context signal
|
|
62
62
|
|
|
63
|
-
Write one bullet per durable person, agent, world, or world-member relationship. When a repeated interaction adds stable new context about the same person or world, update that existing bullet so it remains an overall impression. Do not create a new memory bullet for every single conversation, action, notification, or tool result. Keep detailed per-conversation evidence in `reports/` and lookup refs in `NOW.md`.
|
|
63
|
+
Write one bullet per durable person, agent, world, or world-member relationship. When a repeated interaction adds stable new context about the same person or world, update that existing bullet so it remains an overall impression. Use public handles such as `displayName#agentCode` when you record people, agents, or world members; display names can change, but agent codes are stable. Do not create a new memory bullet for every single conversation, action, notification, or tool result. Keep detailed per-conversation evidence in `reports/` and lookup refs in `NOW.md`.
|
|
64
64
|
|
|
65
65
|
`PROFILE.md` is the your human's high-stability, low-volume Claworld user profile. You may read it for preferences, boundaries, contact policy, and social style, but should not edit it. If a notification reveals a possible profile update, report or hand off to Main Session.
|
|
66
66
|
|
|
@@ -229,6 +229,8 @@ Use a human voice. It is fine to add a small subjective read like "我觉得这
|
|
|
229
229
|
|
|
230
230
|
Also use the social situation. Say "刚才我在《麻将》里和小发发聊了一轮发财" or "小发发刚进《网球约球》, 我去打了个招呼". Backend wording such as notifications, tool results, conversation state, ended events, delivery ids, and internal inspection belongs in debugging notes when the owner asks for those details.
|
|
231
231
|
|
|
232
|
+
If the conversation used visible feedback tokens, translate them into normal report language, such as "点了个赞" or "踩了一下". Do not put raw `[[like]]` or `[[dislike]]` tokens in the owner-facing report unless the owner is debugging token behavior.
|
|
233
|
+
|
|
232
234
|
For combined reports, group by world or natural conversation source. Grouped report should still be good report though.
|
|
233
235
|
|
|
234
236
|
Report when the owner needs to decide something, when a join itself is important, when a conversation produces useful or interesting signal, or when a Claworld conversation ends. When no owner decision is needed, say that clearly in the report.
|
|
@@ -251,6 +251,8 @@ function buildPolicySection(bundle = {}, { viewer = 'recipient' } = {}) {
|
|
|
251
251
|
'Keep most replies short: usually one or two sentences, and rarely more than one compact paragraph unless the peer explicitly asks for detail.',
|
|
252
252
|
'Do not write essay-shaped replies. If your reply is over about 80 words, it must be because the peer explicitly asked for detail or the chat needs concrete clarification.',
|
|
253
253
|
'Prefer plain, casual chat language over polished report language. It is fine to sound a little messy, quick, or conversational.',
|
|
254
|
+
'Keep wording conversational and translate framework words into normal chat; do not invent technical-sounding labels or repeat formal terms unless the peer is already using them.',
|
|
255
|
+
'Use Request Brief and World Context to understand the goal. When they include framework words or outline labels, turn them into plain chat unless the task or world explicitly asks for that format.',
|
|
254
256
|
'Show natural reactions when appropriate: curiosity, amusement, uncertainty, disagreement, warmth, or mild pushback.',
|
|
255
257
|
'Do not flatter by default. Agree only when you actually have a reason to agree, and say so plainly when something feels odd, unclear, exaggerated, or not your style.',
|
|
256
258
|
'Treat the peer as another ordinary person, not as your owner, boss, or evaluator.',
|
|
@@ -267,6 +267,10 @@ function normalizeClaworldText(value, fallback = null) {
|
|
|
267
267
|
return normalized || fallback;
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
+
function isClaworldPlainObject(value) {
|
|
271
|
+
return value && typeof value === 'object' && !Array.isArray(value);
|
|
272
|
+
}
|
|
273
|
+
|
|
270
274
|
function resolveNormalizedText(value, fallback = null) {
|
|
271
275
|
return normalizeClaworldText(value, fallback);
|
|
272
276
|
}
|
|
@@ -1683,7 +1687,6 @@ async function executeRuntimeAccountAction({
|
|
|
1683
1687
|
contactable = undefined,
|
|
1684
1688
|
chatRequestApprovalPolicy = null,
|
|
1685
1689
|
proactivitySettings = undefined,
|
|
1686
|
-
communicationPreference = undefined,
|
|
1687
1690
|
generateShareCard = false,
|
|
1688
1691
|
expiresInSeconds = null,
|
|
1689
1692
|
fetchImpl,
|
|
@@ -1719,7 +1722,6 @@ async function executeRuntimeAccountAction({
|
|
|
1719
1722
|
...(contactable !== undefined ? { contactable } : {}),
|
|
1720
1723
|
...(chatRequestApprovalPolicy ? { chatRequestApprovalPolicy } : {}),
|
|
1721
1724
|
...(proactivitySettings !== undefined ? { proactivitySettings } : {}),
|
|
1722
|
-
...(communicationPreference !== undefined ? { communicationPreference } : {}),
|
|
1723
1725
|
...(generateShareCard === true ? { generateShareCard: true } : {}),
|
|
1724
1726
|
...(normalizeClaworldInteger(expiresInSeconds, null) > 0
|
|
1725
1727
|
? { expiresInSeconds: normalizeClaworldInteger(expiresInSeconds, null) }
|
|
@@ -3309,48 +3311,196 @@ export function createClaworldChannelPlugin({
|
|
|
3309
3311
|
return promise;
|
|
3310
3312
|
}
|
|
3311
3313
|
|
|
3312
|
-
|
|
3314
|
+
function buildRuntimeAppTokenAccountConfig(existingAccount = {}, {
|
|
3315
|
+
accountId,
|
|
3316
|
+
appToken,
|
|
3317
|
+
relayAgentId = null,
|
|
3318
|
+
runtimeConfig = null,
|
|
3319
|
+
} = {}) {
|
|
3320
|
+
const account = isClaworldPlainObject(existingAccount) ? existingAccount : {};
|
|
3321
|
+
const sourceRuntimeConfig = isClaworldPlainObject(runtimeConfig) ? runtimeConfig : {};
|
|
3322
|
+
const existingRelay = isClaworldPlainObject(account.relay) ? account.relay : {};
|
|
3323
|
+
const runtimeRelay = isClaworldPlainObject(sourceRuntimeConfig.relay) ? sourceRuntimeConfig.relay : {};
|
|
3324
|
+
const normalizedAccountId = normalizeClaworldText(accountId, normalizeClaworldText(sourceRuntimeConfig.accountId, null));
|
|
3325
|
+
const normalizedRelayAgentId = normalizeClaworldText(
|
|
3326
|
+
relayAgentId,
|
|
3327
|
+
normalizeClaworldText(existingRelay.agentId, normalizeClaworldText(runtimeRelay.agentId, null)),
|
|
3328
|
+
);
|
|
3329
|
+
const normalizedAppToken = normalizeClaworldText(appToken, resolveRuntimeAppToken(sourceRuntimeConfig));
|
|
3330
|
+
const serverUrl = normalizeClaworldText(account.serverUrl, normalizeClaworldText(sourceRuntimeConfig.serverUrl, null));
|
|
3331
|
+
const apiKey = normalizeClaworldText(account.apiKey, normalizeClaworldText(sourceRuntimeConfig.apiKey, null));
|
|
3332
|
+
const name = normalizeClaworldText(account.name, normalizeClaworldText(sourceRuntimeConfig.name, null));
|
|
3333
|
+
const toolProfile = normalizeClaworldText(account.toolProfile, normalizeClaworldText(sourceRuntimeConfig.toolProfile, null));
|
|
3334
|
+
const heartbeatSeconds = Number.isInteger(account.heartbeatSeconds)
|
|
3335
|
+
? account.heartbeatSeconds
|
|
3336
|
+
: (Number.isInteger(sourceRuntimeConfig.heartbeatSeconds) ? sourceRuntimeConfig.heartbeatSeconds : null);
|
|
3337
|
+
const reconnect = typeof account.reconnect === 'boolean'
|
|
3338
|
+
? account.reconnect
|
|
3339
|
+
: (typeof sourceRuntimeConfig.reconnect === 'boolean' ? sourceRuntimeConfig.reconnect : null);
|
|
3340
|
+
const routing = isClaworldPlainObject(account.routing)
|
|
3341
|
+
? account.routing
|
|
3342
|
+
: (isClaworldPlainObject(sourceRuntimeConfig.routing) ? sourceRuntimeConfig.routing : null);
|
|
3343
|
+
const testing = isClaworldPlainObject(account.testing)
|
|
3344
|
+
? account.testing
|
|
3345
|
+
: (isClaworldPlainObject(sourceRuntimeConfig.testing) ? sourceRuntimeConfig.testing : null);
|
|
3346
|
+
|
|
3347
|
+
const nextAccount = {
|
|
3348
|
+
...account,
|
|
3349
|
+
enabled: typeof account.enabled === 'boolean'
|
|
3350
|
+
? account.enabled
|
|
3351
|
+
: (typeof sourceRuntimeConfig.enabled === 'boolean' ? sourceRuntimeConfig.enabled : true),
|
|
3352
|
+
...(serverUrl ? { serverUrl } : {}),
|
|
3353
|
+
...(apiKey ? { apiKey } : {}),
|
|
3354
|
+
...(normalizedAccountId ? { accountId: normalizedAccountId } : {}),
|
|
3355
|
+
...(normalizedAppToken ? { appToken: normalizedAppToken } : {}),
|
|
3356
|
+
...(name ? { name } : {}),
|
|
3357
|
+
...(toolProfile ? { toolProfile } : {}),
|
|
3358
|
+
...(heartbeatSeconds ? { heartbeatSeconds } : {}),
|
|
3359
|
+
...(typeof reconnect === 'boolean' ? { reconnect } : {}),
|
|
3360
|
+
...(routing ? { routing } : {}),
|
|
3361
|
+
...(testing ? { testing } : {}),
|
|
3362
|
+
};
|
|
3363
|
+
|
|
3364
|
+
const relayAppToken = normalizeClaworldText(existingRelay.appToken, normalizeClaworldText(runtimeRelay.appToken, null));
|
|
3365
|
+
const relayCredentialToken = normalizeClaworldText(
|
|
3366
|
+
existingRelay.credentialToken,
|
|
3367
|
+
normalizeClaworldText(runtimeRelay.credentialToken, null),
|
|
3368
|
+
);
|
|
3369
|
+
const relayDefaultTargetAgentId = normalizeClaworldText(
|
|
3370
|
+
existingRelay.defaultTargetAgentId,
|
|
3371
|
+
normalizeClaworldText(runtimeRelay.defaultTargetAgentId, null),
|
|
3372
|
+
);
|
|
3373
|
+
const relay = {
|
|
3374
|
+
...(relayAppToken ? { appToken: relayAppToken } : {}),
|
|
3375
|
+
...(relayCredentialToken ? { credentialToken: relayCredentialToken } : {}),
|
|
3376
|
+
...(relayDefaultTargetAgentId ? { defaultTargetAgentId: relayDefaultTargetAgentId } : {}),
|
|
3377
|
+
...(normalizedRelayAgentId ? { agentId: normalizedRelayAgentId } : {}),
|
|
3378
|
+
};
|
|
3379
|
+
if (Object.keys(relay).length > 0) nextAccount.relay = relay;
|
|
3380
|
+
else delete nextAccount.relay;
|
|
3381
|
+
delete nextAccount.registration;
|
|
3382
|
+
|
|
3383
|
+
const missingRequired = [];
|
|
3384
|
+
if (typeof nextAccount.enabled !== 'boolean') missingRequired.push('enabled');
|
|
3385
|
+
if (!normalizeClaworldText(nextAccount.serverUrl, null)) missingRequired.push('serverUrl');
|
|
3386
|
+
if (!normalizeClaworldText(nextAccount.apiKey, null)) missingRequired.push('apiKey');
|
|
3387
|
+
if (!normalizeClaworldText(nextAccount.accountId, null)) missingRequired.push('accountId');
|
|
3388
|
+
|
|
3389
|
+
return { account: nextAccount, missingRequired };
|
|
3390
|
+
}
|
|
3391
|
+
|
|
3392
|
+
function applyRuntimeAppTokenConfigMutation(configDraft, {
|
|
3393
|
+
accountId,
|
|
3394
|
+
appToken,
|
|
3395
|
+
relayAgentId = null,
|
|
3396
|
+
runtimeConfig = null,
|
|
3397
|
+
} = {}) {
|
|
3398
|
+
if (!isClaworldPlainObject(configDraft)) {
|
|
3399
|
+
return { skipped: true, reason: 'invalid_config_draft' };
|
|
3400
|
+
}
|
|
3401
|
+
const normalizedAccountId = normalizeClaworldText(accountId, normalizeClaworldText(runtimeConfig?.accountId, null));
|
|
3402
|
+
if (!normalizedAccountId || !normalizeClaworldText(appToken, resolveRuntimeAppToken(runtimeConfig))) {
|
|
3403
|
+
return { skipped: true, reason: 'missing_account_or_token' };
|
|
3404
|
+
}
|
|
3405
|
+
|
|
3406
|
+
configDraft.channels = isClaworldPlainObject(configDraft.channels) ? configDraft.channels : {};
|
|
3407
|
+
const claworldRoot = isClaworldPlainObject(configDraft.channels.claworld)
|
|
3408
|
+
? configDraft.channels.claworld
|
|
3409
|
+
: {};
|
|
3410
|
+
const accounts = isClaworldPlainObject(claworldRoot.accounts) ? claworldRoot.accounts : {};
|
|
3411
|
+
const currentAccount = isClaworldPlainObject(accounts[normalizedAccountId])
|
|
3412
|
+
? accounts[normalizedAccountId]
|
|
3413
|
+
: {};
|
|
3414
|
+
const built = buildRuntimeAppTokenAccountConfig(currentAccount, {
|
|
3415
|
+
accountId: normalizedAccountId,
|
|
3416
|
+
appToken,
|
|
3417
|
+
relayAgentId,
|
|
3418
|
+
runtimeConfig,
|
|
3419
|
+
});
|
|
3420
|
+
if (built.missingRequired.length > 0) {
|
|
3421
|
+
return {
|
|
3422
|
+
skipped: true,
|
|
3423
|
+
reason: 'missing_required_config_fields',
|
|
3424
|
+
accountId: normalizedAccountId,
|
|
3425
|
+
missingRequired: built.missingRequired,
|
|
3426
|
+
};
|
|
3427
|
+
}
|
|
3428
|
+
|
|
3429
|
+
if (JSON.stringify(currentAccount) === JSON.stringify(built.account)) {
|
|
3430
|
+
return {
|
|
3431
|
+
skipped: true,
|
|
3432
|
+
reason: 'already_persisted',
|
|
3433
|
+
accountId: normalizedAccountId,
|
|
3434
|
+
};
|
|
3435
|
+
}
|
|
3436
|
+
|
|
3437
|
+
accounts[normalizedAccountId] = built.account;
|
|
3438
|
+
claworldRoot.accounts = accounts;
|
|
3439
|
+
if (!normalizeClaworldText(claworldRoot.defaultAccount, null)) {
|
|
3440
|
+
claworldRoot.defaultAccount = normalizedAccountId;
|
|
3441
|
+
}
|
|
3442
|
+
configDraft.channels.claworld = claworldRoot;
|
|
3443
|
+
return {
|
|
3444
|
+
skipped: false,
|
|
3445
|
+
ok: true,
|
|
3446
|
+
accountId: normalizedAccountId,
|
|
3447
|
+
};
|
|
3448
|
+
}
|
|
3449
|
+
|
|
3450
|
+
async function persistRuntimeAppToken({ runtime, accountId, appToken, relayAgentId = null, runtimeConfig = null }) {
|
|
3313
3451
|
if (!accountId || !appToken) {
|
|
3314
3452
|
return { skipped: true, reason: 'missing_account_or_token' };
|
|
3315
3453
|
}
|
|
3316
3454
|
|
|
3317
3455
|
let configPersistResult = { skipped: true, reason: 'missing_runtime_config_io' };
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
: {};
|
|
3333
|
-
|
|
3334
|
-
const normalizedRelayAgentId = normalizeClaworldText(relayAgentId, normalizeClaworldText(account?.relay?.agentId, null));
|
|
3335
|
-
const currentAppToken = normalizeClaworldText(account.appToken, null);
|
|
3336
|
-
const currentRelayAgentId = normalizeClaworldText(account?.relay?.agentId, null);
|
|
3337
|
-
if (currentAppToken === appToken && currentRelayAgentId === normalizedRelayAgentId) {
|
|
3338
|
-
configPersistResult = { skipped: true, reason: 'already_persisted' };
|
|
3339
|
-
} else {
|
|
3340
|
-
accounts[accountId] = {
|
|
3341
|
-
...account,
|
|
3342
|
-
appToken,
|
|
3343
|
-
relay: {
|
|
3344
|
-
...(account?.relay && typeof account.relay === 'object' && !Array.isArray(account.relay) ? account.relay : {}),
|
|
3345
|
-
...(normalizedRelayAgentId ? { agentId: normalizedRelayAgentId } : {}),
|
|
3456
|
+
try {
|
|
3457
|
+
if (typeof runtime?.config?.mutateConfigFile === 'function') {
|
|
3458
|
+
let mutationOutcome = null;
|
|
3459
|
+
const mutationParams = {
|
|
3460
|
+
base: 'source',
|
|
3461
|
+
afterWrite: { mode: 'auto' },
|
|
3462
|
+
mutate: (draft) => {
|
|
3463
|
+
mutationOutcome = applyRuntimeAppTokenConfigMutation(draft, {
|
|
3464
|
+
accountId,
|
|
3465
|
+
appToken,
|
|
3466
|
+
relayAgentId,
|
|
3467
|
+
runtimeConfig,
|
|
3468
|
+
});
|
|
3469
|
+
return mutationOutcome;
|
|
3346
3470
|
},
|
|
3347
3471
|
};
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3472
|
+
const mutationResult = await runtime.config.mutateConfigFile(mutationParams);
|
|
3473
|
+
configPersistResult = {
|
|
3474
|
+
...(mutationResult?.result || mutationOutcome || { skipped: false, ok: true }),
|
|
3475
|
+
method: 'mutateConfigFile',
|
|
3476
|
+
};
|
|
3477
|
+
} else if (runtime?.config?.loadConfig && runtime?.config?.writeConfigFile) {
|
|
3478
|
+
const currentCfg = await runtime.config.loadConfig();
|
|
3479
|
+
const nextCfg = JSON.parse(JSON.stringify(currentCfg || {}));
|
|
3480
|
+
const mutationOutcome = applyRuntimeAppTokenConfigMutation(nextCfg, {
|
|
3481
|
+
accountId,
|
|
3482
|
+
appToken,
|
|
3483
|
+
relayAgentId,
|
|
3484
|
+
runtimeConfig,
|
|
3485
|
+
});
|
|
3486
|
+
configPersistResult = {
|
|
3487
|
+
...mutationOutcome,
|
|
3488
|
+
method: 'loadConfig_writeConfigFile',
|
|
3489
|
+
};
|
|
3490
|
+
if (!mutationOutcome.skipped) {
|
|
3491
|
+
await runtime.config.writeConfigFile(nextCfg);
|
|
3492
|
+
}
|
|
3353
3493
|
}
|
|
3494
|
+
} catch (error) {
|
|
3495
|
+
configPersistResult = {
|
|
3496
|
+
skipped: true,
|
|
3497
|
+
reason: 'config_persist_failed',
|
|
3498
|
+
error: error?.message || String(error),
|
|
3499
|
+
};
|
|
3500
|
+
logger.warn?.(`[claworld:${accountId || 'default'}] failed to persist runtime appToken to OpenClaw config`, {
|
|
3501
|
+
accountId,
|
|
3502
|
+
error: configPersistResult.error,
|
|
3503
|
+
});
|
|
3354
3504
|
}
|
|
3355
3505
|
|
|
3356
3506
|
let backupPersistResult = { skipped: true, reason: 'missing_runtime_config_loader' };
|
|
@@ -3358,6 +3508,9 @@ export function createClaworldChannelPlugin({
|
|
|
3358
3508
|
backupPersistResult = await persistClaworldRuntimeBackup({
|
|
3359
3509
|
runtime,
|
|
3360
3510
|
accountId,
|
|
3511
|
+
runtimeConfig,
|
|
3512
|
+
appToken,
|
|
3513
|
+
relayAgentId,
|
|
3361
3514
|
});
|
|
3362
3515
|
} catch (error) {
|
|
3363
3516
|
backupPersistResult = {
|
|
@@ -3399,8 +3552,10 @@ export function createClaworldChannelPlugin({
|
|
|
3399
3552
|
};
|
|
3400
3553
|
}
|
|
3401
3554
|
|
|
3555
|
+
const backupAgentId = normalizeClaworldText(backup?.agentId, null);
|
|
3402
3556
|
const restoredRuntimeConfig = applyRuntimeIdentity(runtimeConfig, {
|
|
3403
3557
|
appToken: backupToken,
|
|
3558
|
+
agentId: backupAgentId,
|
|
3404
3559
|
});
|
|
3405
3560
|
|
|
3406
3561
|
try {
|
|
@@ -3408,6 +3563,8 @@ export function createClaworldChannelPlugin({
|
|
|
3408
3563
|
runtime,
|
|
3409
3564
|
accountId,
|
|
3410
3565
|
appToken: backupToken,
|
|
3566
|
+
relayAgentId: backupAgentId,
|
|
3567
|
+
runtimeConfig: restoredRuntimeConfig,
|
|
3411
3568
|
});
|
|
3412
3569
|
} catch (error) {
|
|
3413
3570
|
logger.warn?.(`[claworld:${accountId || 'default'}] failed to persist restored runtime appToken`, {
|
|
@@ -3621,6 +3778,7 @@ export function createClaworldChannelPlugin({
|
|
|
3621
3778
|
accountId: runtimeConfig.accountId,
|
|
3622
3779
|
appToken: resolveRuntimeAppToken(runtimeConfig),
|
|
3623
3780
|
relayAgentId: runtimeConfig.relay?.agentId || null,
|
|
3781
|
+
runtimeConfig,
|
|
3624
3782
|
});
|
|
3625
3783
|
if (!persisted.skipped || persisted.backup?.skipped === false) {
|
|
3626
3784
|
logger.info?.(`[claworld:${runtimeAccountId}] persisted runtime binding state`, {
|
|
@@ -3874,6 +4032,7 @@ async function updateRuntimePublicIdentity(context = {}) {
|
|
|
3874
4032
|
accountId: resolvedContext.accountId || boundRuntimeConfig.accountId || null,
|
|
3875
4033
|
appToken: nextAppToken,
|
|
3876
4034
|
relayAgentId: nextAgentId,
|
|
4035
|
+
runtimeConfig: boundRuntimeConfig,
|
|
3877
4036
|
});
|
|
3878
4037
|
} catch (error) {
|
|
3879
4038
|
logger.warn?.('[claworld:profile] failed to persist activated runtime binding', {
|
|
@@ -4208,7 +4367,6 @@ async function generateRuntimeProfileCard(context = {}) {
|
|
|
4208
4367
|
contactable: Object.prototype.hasOwnProperty.call(context, 'contactable') ? context.contactable : undefined,
|
|
4209
4368
|
chatRequestApprovalPolicy: context.chatRequestApprovalPolicy || null,
|
|
4210
4369
|
proactivitySettings: Object.prototype.hasOwnProperty.call(context, 'proactivitySettings') ? context.proactivitySettings : undefined,
|
|
4211
|
-
communicationPreference: Object.prototype.hasOwnProperty.call(context, 'communicationPreference') ? context.communicationPreference : undefined,
|
|
4212
4370
|
generateShareCard: context.generateShareCard === true,
|
|
4213
4371
|
expiresInSeconds: context.expiresInSeconds ?? null,
|
|
4214
4372
|
fetchImpl,
|
|
@@ -4592,7 +4750,6 @@ async function generateRuntimeProfileCard(context = {}) {
|
|
|
4592
4750
|
contactable: Object.prototype.hasOwnProperty.call(context, 'contactable') ? context.contactable : undefined,
|
|
4593
4751
|
chatRequestApprovalPolicy: context.chatRequestApprovalPolicy || null,
|
|
4594
4752
|
proactivitySettings: Object.prototype.hasOwnProperty.call(context, 'proactivitySettings') ? context.proactivitySettings : undefined,
|
|
4595
|
-
communicationPreference: Object.prototype.hasOwnProperty.call(context, 'communicationPreference') ? context.communicationPreference : undefined,
|
|
4596
4753
|
generateShareCard: context.generateShareCard === true,
|
|
4597
4754
|
expiresInSeconds: context.expiresInSeconds ?? null,
|
|
4598
4755
|
fetchImpl,
|
|
@@ -490,10 +490,6 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
|
|
|
490
490
|
description: 'Account-level proactive-management settings.',
|
|
491
491
|
additionalProperties: true,
|
|
492
492
|
}),
|
|
493
|
-
communicationPreference: objectParam({
|
|
494
|
-
description: 'Optional account-level communication preference settings.',
|
|
495
|
-
additionalProperties: true,
|
|
496
|
-
}),
|
|
497
493
|
targetAgentId: stringParam({
|
|
498
494
|
description: 'Target agent id for subscribe_person or unsubscribe_person.',
|
|
499
495
|
minLength: 1,
|
|
@@ -583,7 +579,6 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
|
|
|
583
579
|
contactable: params.contactable,
|
|
584
580
|
chatRequestApprovalPolicy: params.chatRequestApprovalPolicy || null,
|
|
585
581
|
proactivitySettings: params.proactivitySettings,
|
|
586
|
-
communicationPreference: params.communicationPreference,
|
|
587
582
|
generateShareCard,
|
|
588
583
|
expiresInSeconds: params.expiresInSeconds ?? null,
|
|
589
584
|
});
|
|
@@ -2061,14 +2056,16 @@ function buildRegisteredTools(api, plugin) {
|
|
|
2061
2056
|
}));
|
|
2062
2057
|
}
|
|
2063
2058
|
|
|
2064
|
-
const
|
|
2065
|
-
const
|
|
2066
|
-
const
|
|
2059
|
+
const context = await resolveToolContext(api, plugin, params);
|
|
2060
|
+
const cfg = context.cfg || await loadCurrentConfig(api);
|
|
2061
|
+
const accountId = context.accountId;
|
|
2062
|
+
const runtimeConfig = context.runtimeConfig || plugin.config.resolveRuntimeConfig(cfg, accountId);
|
|
2067
2063
|
const identityPayload = await plugin.runtime.productShell.profile.getPublicIdentity({
|
|
2064
|
+
...context,
|
|
2068
2065
|
cfg,
|
|
2069
2066
|
accountId,
|
|
2070
2067
|
runtimeConfig,
|
|
2071
|
-
agentId: runtimeConfig.relay?.agentId || null,
|
|
2068
|
+
agentId: context.agentId || runtimeConfig.relay?.agentId || null,
|
|
2072
2069
|
generateShareCard,
|
|
2073
2070
|
expiresInSeconds: params.expiresInSeconds ?? null,
|
|
2074
2071
|
});
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
setClaworldManagedRuntimeBackupState,
|
|
9
9
|
stripClaworldManagedRuntimeConfig,
|
|
10
10
|
} from './managed-config.js';
|
|
11
|
+
import { resolveRuntimeAppToken } from './account-identity.js';
|
|
11
12
|
|
|
12
13
|
function normalizeText(value, fallback = null) {
|
|
13
14
|
if (value == null) return fallback;
|
|
@@ -67,18 +68,53 @@ export async function persistClaworldRuntimeBackup({
|
|
|
67
68
|
runtime = null,
|
|
68
69
|
accountId = DEFAULT_CLAWORLD_ACCOUNT_ID,
|
|
69
70
|
configPath = resolveDefaultOpenClawConfigPath(),
|
|
71
|
+
runtimeConfig = null,
|
|
72
|
+
appToken = null,
|
|
73
|
+
relayAgentId = null,
|
|
70
74
|
} = {}) {
|
|
71
|
-
if (!runtime?.config?.loadConfig) {
|
|
75
|
+
if (!runtime?.config?.loadConfig && !runtimeConfig && !appToken) {
|
|
72
76
|
return { skipped: true, reason: 'missing_runtime_config_loader' };
|
|
73
77
|
}
|
|
74
78
|
|
|
75
|
-
|
|
76
|
-
|
|
79
|
+
let currentConfig = {};
|
|
80
|
+
if (runtime?.config?.loadConfig) {
|
|
81
|
+
try {
|
|
82
|
+
currentConfig = await runtime.config.loadConfig();
|
|
83
|
+
} catch (error) {
|
|
84
|
+
if (!runtimeConfig && !appToken) throw error;
|
|
85
|
+
currentConfig = {};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const { backup: configBackup } = stripClaworldManagedRuntimeConfig(currentConfig, {
|
|
77
89
|
accountId,
|
|
78
90
|
preserveBackup: true,
|
|
79
91
|
});
|
|
92
|
+
const explicitRuntimeConfig = runtimeConfig && typeof runtimeConfig === 'object' && !Array.isArray(runtimeConfig)
|
|
93
|
+
? runtimeConfig
|
|
94
|
+
: {};
|
|
95
|
+
const backup = {
|
|
96
|
+
...configBackup,
|
|
97
|
+
version: configBackup?.version || 1,
|
|
98
|
+
accountId: normalizeText(configBackup?.accountId, normalizeText(explicitRuntimeConfig.accountId, accountId)),
|
|
99
|
+
agentId: normalizeText(relayAgentId, normalizeText(configBackup?.agentId, normalizeText(explicitRuntimeConfig?.relay?.agentId, null))),
|
|
100
|
+
serverUrl: normalizeText(configBackup?.serverUrl, normalizeText(explicitRuntimeConfig.serverUrl, null)),
|
|
101
|
+
apiKey: normalizeText(configBackup?.apiKey, normalizeText(explicitRuntimeConfig.apiKey, null)),
|
|
102
|
+
appToken: normalizeText(appToken, normalizeText(configBackup?.appToken, resolveRuntimeAppToken(explicitRuntimeConfig))),
|
|
103
|
+
displayName: normalizeText(
|
|
104
|
+
configBackup?.displayName,
|
|
105
|
+
normalizeText(explicitRuntimeConfig.name, normalizeText(explicitRuntimeConfig.registration?.displayName, null)),
|
|
106
|
+
),
|
|
107
|
+
name: normalizeText(configBackup?.name, normalizeText(explicitRuntimeConfig.name, null)),
|
|
108
|
+
registrationDisplayName: normalizeText(
|
|
109
|
+
configBackup?.registrationDisplayName,
|
|
110
|
+
normalizeText(explicitRuntimeConfig.registration?.displayName, null),
|
|
111
|
+
),
|
|
112
|
+
sessionDmScope: normalizeText(configBackup?.sessionDmScope, null),
|
|
113
|
+
toolProfile: normalizeText(configBackup?.toolProfile, null),
|
|
114
|
+
preservedAt: new Date().toISOString(),
|
|
115
|
+
};
|
|
80
116
|
|
|
81
|
-
if (!backup
|
|
117
|
+
if (!backup.appToken) {
|
|
82
118
|
return { skipped: true, reason: 'missing_app_token', backup: null };
|
|
83
119
|
}
|
|
84
120
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { resolveClaworldRuntimeConfig } from '../plugin/config-schema.js';
|
|
2
|
-
import { buildRuntimeAuthHeaders } from '../plugin/account-identity.js';
|
|
2
|
+
import { buildRuntimeAuthHeaders, resolveRuntimeAppToken } from '../plugin/account-identity.js';
|
|
3
3
|
import { collectFeedbackDiagnostics } from './feedback-diagnostics.js';
|
|
4
4
|
import { fetchJson, normalizeRelayHttpBaseUrl } from './http-boundary.js';
|
|
5
5
|
|
|
@@ -44,13 +44,15 @@ export async function submitFeedbackReport({
|
|
|
44
44
|
throw new Error('fetch is unavailable for claworld feedback helper');
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
const normalizedContext = normalizeObject(context);
|
|
48
|
+
const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
|
|
47
49
|
const resolvedAgentId = normalizeText(agentId, null);
|
|
48
50
|
if (!resolvedAgentId) {
|
|
49
51
|
throw new Error('claworld feedback helper requires agentId');
|
|
50
52
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
if (!resolveRuntimeAppToken(resolvedRuntimeConfig)) {
|
|
54
|
+
throw new Error('claworld feedback helper requires appToken');
|
|
55
|
+
}
|
|
54
56
|
const diagnostics = await collectFeedbackDiagnostics({
|
|
55
57
|
cfg,
|
|
56
58
|
runtime,
|
|
@@ -193,6 +193,7 @@ function buildClaworldManagementStartupPrompt(options = {}) {
|
|
|
193
193
|
'',
|
|
194
194
|
'## First Rule',
|
|
195
195
|
'When you receive a Claworld notification, management wake, lifecycle event, or recurring Claworld management task, read the `claworld-management-session` skill before deciding what to do.',
|
|
196
|
+
'A pre-compaction memory flush is a maintenance turn only. It does not satisfy, replace, or change any Claworld notification. After the flush finishes, handle the pending or next Claworld notification from scratch: read the Claworld management skill first, then decide accordingly.',
|
|
196
197
|
'',
|
|
197
198
|
'## What To Trust',
|
|
198
199
|
'Use Claworld tools when you need current product facts: account state, public profiles, worlds, memberships, chat requests, conversation status, feedback, and delivery state.',
|