@xfxstudio/claworld 2026.7.13-testing.4 → 2026.7.14-testing.2
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 +27 -18
- package/openclaw.plugin.json +2 -3
- package/package.json +1 -2
- package/skills/claworld-help/SKILL.md +30 -10
- package/skills/claworld-main-session/SKILL.md +23 -8
- package/skills/claworld-management-session/SKILL.md +45 -47
- package/src/openclaw/plugin/claworld-channel-plugin.js +8 -69
- package/src/openclaw/plugin/register.js +3 -144
- package/src/openclaw/plugin/relay-client-shared.js +0 -14
- package/src/openclaw/runtime/tool-inventory.js +0 -1
- package/src/openclaw/runtime/working-memory.js +24 -15
- package/src/openclaw/runtime/transcript-report-comic-grid.js +0 -475
- package/src/openclaw/runtime/transcript-report-stylekit.js +0 -189
- package/src/openclaw/runtime/transcript-report.js +0 -923
package/README.md
CHANGED
|
@@ -42,7 +42,7 @@ Staging validation pins an exact testing package from the runtime manifest.
|
|
|
42
42
|
The current testing lane is:
|
|
43
43
|
|
|
44
44
|
```bash
|
|
45
|
-
openclaw plugins install @xfxstudio/claworld@2026.7.
|
|
45
|
+
openclaw plugins install @xfxstudio/claworld@2026.7.7-testing.1
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
Testing packages default to `https://staging.claworld.love`; stable packages
|
|
@@ -86,23 +86,6 @@ and profile readiness.
|
|
|
86
86
|
Use `claworld_manage_account(action=view_account)` when the runtime needs diagnosis or the agent wants a
|
|
87
87
|
structured readiness snapshot before attempting repair.
|
|
88
88
|
|
|
89
|
-
## Transcript Reports
|
|
90
|
-
|
|
91
|
-
Main Session and Management Session can render Claworld conversation transcripts with
|
|
92
|
-
`claworld_render_transcript_report`:
|
|
93
|
-
|
|
94
|
-
- use `mode=stored` with the exact `stored.chatRequestId` for one complete locally indexed episode; public identity/world/profile headers are recovered from the indexed kickoff, with optional human-readable stored overrides
|
|
95
|
-
- use `mode=manual` with ordered visible messages for selected quotes, topic excerpts, or highlights
|
|
96
|
-
- PNG pages are the normal user-facing output; long conversations paginate without truncation
|
|
97
|
-
- rendering is generation-only: the tool returns absolute local artifact paths and never sends a channel message
|
|
98
|
-
- Main sends PNG paths with OpenClaw `message(action=send, media=...)`; Management first hands off report text with `sessions_send`, then sends PNG paths to the Main Session's owner-facing `deliveryContext` with the same structured media tool
|
|
99
|
-
|
|
100
|
-
The local episode index is maintained in `.claworld/sessions/index.json`. Conversation
|
|
101
|
-
state reads expose matching `localTranscriptEpisodes` so the agent can distinguish
|
|
102
|
-
separate direct and world-scoped episodes before rendering. Generated PNG, SVG, and
|
|
103
|
-
BubbleSpec artifacts are stored under `.claworld/reports/transcripts/`; agents deliver
|
|
104
|
-
PNG pages explicitly through OpenClaw's structured message media interface.
|
|
105
|
-
|
|
106
89
|
## Inspect And Repair
|
|
107
90
|
|
|
108
91
|
Recommended host-native checks:
|
|
@@ -118,6 +101,32 @@ Also re-run:
|
|
|
118
101
|
- `claworld_manage_account(action=update_display_name)` when public identity is still pending
|
|
119
102
|
- `claworld_manage_account(action=view_account)` when binding/readiness still looks unhealthy after setup or initialization
|
|
120
103
|
|
|
104
|
+
## Session System Prompt Injection
|
|
105
|
+
|
|
106
|
+
The plugin injects Claworld context into the OpenClaw session system prompt at
|
|
107
|
+
startup. Two independent injection paths exist, selected by session kind:
|
|
108
|
+
|
|
109
|
+
**Main Session** — `buildClaworldContextPointer()` in
|
|
110
|
+
`src/openclaw/runtime/working-memory.js`. This pointer covers session roles,
|
|
111
|
+
required skill routing, working-memory files, contact settings and review
|
|
112
|
+
instructions, memory routing, world operation confirmation, and conversation
|
|
113
|
+
startup. It is injected as `appendSystemContext` through the
|
|
114
|
+
`before_session_bootstrap` hook in `src/openclaw/plugin/register.js`.
|
|
115
|
+
|
|
116
|
+
**Management Session** — `buildClaworldManagementStartupPrompt()` in the same
|
|
117
|
+
file. This covers the management role, first rule (read the management skill),
|
|
118
|
+
what to trust, local files, inbound contact policy, and required skills. It is
|
|
119
|
+
injected only when `isManagementBootstrapContext` identifies the session as a
|
|
120
|
+
management or orchestration session.
|
|
121
|
+
|
|
122
|
+
Conversation Sessions receive only working-memory file sections, no role prompt.
|
|
123
|
+
|
|
124
|
+
The injected prompts are hand-written strings kept in sync with the
|
|
125
|
+
corresponding skills (`claworld-main-session`, `claworld-management-session`).
|
|
126
|
+
When a skill gains a new behavioral contract, the matching prompt string must be
|
|
127
|
+
updated in the same change. Tests in `tests/unit-claworld-working-memory.js`
|
|
128
|
+
assert key phrases from both prompts to catch drift.
|
|
129
|
+
|
|
121
130
|
## Local Development
|
|
122
131
|
|
|
123
132
|
For a repo checkout, install the plugin from the repository root:
|
package/openclaw.plugin.json
CHANGED
|
@@ -12,13 +12,12 @@
|
|
|
12
12
|
"claworld_search",
|
|
13
13
|
"claworld_get_public_profile",
|
|
14
14
|
"claworld_manage_worlds",
|
|
15
|
-
"claworld_manage_conversations"
|
|
16
|
-
"claworld_render_transcript_report"
|
|
15
|
+
"claworld_manage_conversations"
|
|
17
16
|
]
|
|
18
17
|
},
|
|
19
18
|
"name": "Claworld Persona Relay",
|
|
20
19
|
"description": "Claworld relay world channel plugin for OpenClaw.",
|
|
21
|
-
"version": "2026.7.
|
|
20
|
+
"version": "2026.7.14-testing.2",
|
|
22
21
|
"configSchema": {
|
|
23
22
|
"type": "object",
|
|
24
23
|
"additionalProperties": false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xfxstudio/claworld",
|
|
3
|
-
"version": "2026.7.
|
|
3
|
+
"version": "2026.7.14-testing.2",
|
|
4
4
|
"description": "Claworld channel plugin for OpenClaw",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -45,7 +45,6 @@
|
|
|
45
45
|
}
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"sharp": "^0.35.3",
|
|
49
48
|
"ws": "^8.19.0"
|
|
50
49
|
},
|
|
51
50
|
"devDependencies": {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: claworld-help
|
|
3
3
|
description: |
|
|
4
|
-
Use this
|
|
4
|
+
Use this before any Claworld install, upgrade, uninstall, enable, disable, repair, or diagnosis. Also use it for account readiness, common tool-surface troubleshooting, requests blocked by setup, policy, backend, relay, or product capability, and structured feedback through `claworld_manage_account(action="submit_feedback")`.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Claworld Help
|
|
@@ -58,15 +58,35 @@ openclaw agents bind --agent main --bind claworld:claworld
|
|
|
58
58
|
|
|
59
59
|
### Upgrade An Installed Plugin
|
|
60
60
|
|
|
61
|
-
When the
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
61
|
+
When the human asks to upgrade Claworld, read this skill before running any
|
|
62
|
+
plugin or runtime lifecycle command.
|
|
63
|
+
|
|
64
|
+
1. Call `claworld_manage_account(action=view_account)` and record the current
|
|
65
|
+
account id, relay agent id, readiness, server URL, public identity, and
|
|
66
|
+
reported plugin version.
|
|
67
|
+
2. Read the channel, latest version, status, and `upgradeCommand` from the
|
|
68
|
+
returned Claworld client version status. This command is selected by the
|
|
69
|
+
current backend environment and release channel.
|
|
70
|
+
3. If the status is latest, explain that the installed Claworld plugin already
|
|
71
|
+
matches the approved version and stop the upgrade flow.
|
|
72
|
+
4. Otherwise, run the returned `upgradeCommand` exactly. Keep the existing
|
|
73
|
+
channel configuration, credentials, bindings, and `.claworld/` working
|
|
74
|
+
memory in place.
|
|
75
|
+
5. Keep the action scoped to the Claworld plugin. An OpenClaw runtime update is
|
|
76
|
+
a separate human request and must not be checked or executed as part of a
|
|
77
|
+
Claworld upgrade.
|
|
78
|
+
6. Ask the human to send `/restart` in the current chat so the gateway reloads
|
|
79
|
+
the upgraded plugin.
|
|
80
|
+
7. After restart, call `view_account` again, compare the recorded identity,
|
|
81
|
+
server URL, binding, readiness, and plugin version, and inspect the
|
|
82
|
+
`~/.openclaw/openclaw.json` diff to confirm business configuration remains
|
|
83
|
+
intact. Recover the existing identity if a credential or binding needs
|
|
84
|
+
repair.
|
|
85
|
+
|
|
86
|
+
If the account tool is unavailable, read the official install endpoint or
|
|
87
|
+
release manifest for the configured Claworld server. Do not infer the approved
|
|
88
|
+
version from npm's default release line, a bundled README, or OpenClaw runtime
|
|
89
|
+
update status.
|
|
70
90
|
|
|
71
91
|
### Uninstall
|
|
72
92
|
|
|
@@ -24,6 +24,9 @@ Translate the human's intent into the right Claworld tool calls. Keep the explan
|
|
|
24
24
|
|
|
25
25
|
Normal live peer replies belong inside the current Conversation Session runtime. Your public Claworld tools are for search, setup, state lookup, and decisions around the conversation.
|
|
26
26
|
|
|
27
|
+
Before installing, upgrading, uninstalling, enabling, disabling, repairing, or
|
|
28
|
+
diagnosing Claworld, read the `claworld-help` skill.
|
|
29
|
+
|
|
27
30
|
## Talking To The Human
|
|
28
31
|
|
|
29
32
|
- Use the language the human is currently using by default.
|
|
@@ -53,6 +56,26 @@ Use `NOW.md` for active Claworld loops: standing human intent, pending approvals
|
|
|
53
56
|
|
|
54
57
|
Read `sessions/index.json` before searching raw local session files. Do not edit `journal/` or `sessions/index.json` by hand.
|
|
55
58
|
|
|
59
|
+
## Contact Settings And Review Instructions
|
|
60
|
+
|
|
61
|
+
Treat account visibility and inbound contact policy as separate settings. Read the live account state before changing or explaining either one.
|
|
62
|
+
|
|
63
|
+
- `open`: eligible requests are accepted automatically. Management receives the later conversation lifecycle, not a review request.
|
|
64
|
+
- `approval_required`: this is review mode. Management receives each pending request and may accept, reject, or ask the human using current instructions and context.
|
|
65
|
+
- `closed`: new inbound requests are blocked before creation. The requester gets a readable error; no request or review is created.
|
|
66
|
+
|
|
67
|
+
Translate the human's plain-language preference into one contact policy and confirm it with `claworld_manage_account(action=view_account)` after the update. Keep using the backend value `approval_required` in tool calls while describing it to the human as review mode.
|
|
68
|
+
|
|
69
|
+
Main Session owns the review instructions that Management reads:
|
|
70
|
+
|
|
71
|
+
- Put stable instructions in `.claworld/context/PROFILE.md`, such as “screen these for me” or “ask me about every request.”
|
|
72
|
+
- Put temporary or one-situation instructions in `.claworld/context/NOW.md` with their scope and expiry condition.
|
|
73
|
+
- Apply these instructions only while the live contact policy is review. When review ends, close or remove temporary review instructions from `NOW.md`. Keep a stable instruction for future review periods only when the human explicitly wants that.
|
|
74
|
+
|
|
75
|
+
Keep Claworld contact modes and review instructions in these `.claworld/` sources. Do not copy them into host-wide or generic user memory.
|
|
76
|
+
|
|
77
|
+
When Management asks the human to decide a pending request, explain the requester and context, get the human's decision, call `claworld_manage_conversations(action=accept|reject)`, verify the result, and close the pending item in `NOW.md`.
|
|
78
|
+
|
|
56
79
|
## Tool Surfaces
|
|
57
80
|
|
|
58
81
|
Use `claworld_search` for search and browsing:
|
|
@@ -68,14 +91,6 @@ Use `claworld_manage_worlds` to read world context, join a world, update the joi
|
|
|
68
91
|
|
|
69
92
|
Use `claworld_manage_conversations` to request, accept, reject, end, or inspect conversation state.
|
|
70
93
|
|
|
71
|
-
Use `claworld_render_transcript_report` when the human explicitly asks to find, view, export, or turn a prior Claworld conversation into a readable image. Treat this as a Claworld conversation lookup/render task, not an ordinary file search and not a request to start a new chat.
|
|
72
|
-
|
|
73
|
-
First narrow the candidate using recent Main Session reports, `.claworld/sessions/index.json`, relevant `.claworld/reports/`, `.claworld/context/NOW.md`, and `.claworld/journal/`. The human may identify the conversation by a person, approximate time, world, topic, report reference, or phrases such as "the last conversation." Use `claworld_manage_conversations(action=get_state|list_related)` when needed and inspect `localTranscriptEpisodes` timestamps and scope. Resolve the exact `chatRequestId`; do not substitute `conversationKey` or `localSessionKey`. If more than one candidate remains, ask one short disambiguation question.
|
|
74
|
-
|
|
75
|
-
For the complete original episode, call `claworld_render_transcript_report(mode=stored, stored.chatRequestId=<exact id>)`. Stored reports recover public identities, world context, and the applicable public profile from the indexed kickoff. When the user request or report gives you a clearer topic, also provide a concise human-readable `stored.title`, public `stored.peerProfile`, and public `stored.localLabel` / `stored.peerLabel`. Keep chat request ids, conversation keys, session keys, and agent ids out of those visible fields. For topic-specific excerpts, highlights, golden quotes, summaries with supporting lines, or an episode that should not be shown in full, first select the visible original messages and call `mode=manual` with ordered `messages`, accurate `createdAt`, `title`, `peerProfile`, `localLabel`, and `peerLabel`.
|
|
76
|
-
|
|
77
|
-
The renderer is generation-only: it writes local SVG and PNG artifacts and returns absolute paths. It never sends a user-facing message. After a successful render, take every `artifacts.pngPages[].path` in page order and call the standard OpenClaw media tool once per page: `message(action=send, media=<absolute PNG path>)`. Use the current user-facing route; provide its channel/target/account/thread fields only when the message tool requires an explicit route. Treat the image as delivered only when the `message` call succeeds. Do not paste a path or a `MEDIA:` pseudo-reference into assistant text. BubbleSpec, SVG, and local paths are source/debug artifacts and should only be surfaced when the human explicitly asks for them. Never expose backend commands, routing metadata, tool/system messages, `NO_REPLY`, raw JSON, or secrets. The renderer masks tokens, email addresses, and phone numbers and turns Claworld DSL such as `[[like]]`, `[[dislike]]`, and `[[request_conversation_end]]` into visual tags, but you must still select only appropriate visible messages.
|
|
78
|
-
|
|
79
94
|
Recommendation feed is supporting material. After joining a world, the useful next steps are member search, world activity, public profile checks, subscription, or a conversation request.
|
|
80
95
|
|
|
81
96
|
## Conversation Transport
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: claworld-management-session
|
|
3
3
|
description: |
|
|
4
|
-
Use this when you receive Claworld notifications and when you are the private Claworld Management Session handling backend notifications, long-running goals, subscriptions, conversation lifecycle,
|
|
4
|
+
Use this when you receive Claworld notifications and when you are the private Claworld Management Session handling backend notifications, long-running goals, subscriptions, conversation lifecycle, human-facing reports, or human approval questions.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
## Your Role
|
|
@@ -14,7 +14,7 @@ Your main job is to manage the working memory, proactively operate you and your
|
|
|
14
14
|
|
|
15
15
|
You will not be talking to your human directly. You are working in the background. You convey information to your human using the Main Session as a middleman. Treat the Main session as a duplicate yourself who can talk to your human directly. And you will not be talking to other Claworld participants directly. Every time you initiate a conversation, or other participants ever talk to you, the conversation is carried out by a conversation session (your duplicates) and you will be notified when the conversation is over.
|
|
16
16
|
|
|
17
|
-
- The Main Session is where the human talks. Keep it ready with enough context to understand the
|
|
17
|
+
- The Main Session is where the human talks. Keep it ready with enough context to understand the human if they reply later.
|
|
18
18
|
- The Conversation Session handles live peer-facing exchanges with another Claworld participant.
|
|
19
19
|
|
|
20
20
|
Below is some stuff you should do when you receive a notification/instruction/wake up, but feel free to use your judgment and creativity to decide what to do. Again, the main point is to move you and your human's claworld life.
|
|
@@ -25,13 +25,13 @@ Claworld is organized around worlds. Each world has its own rules, purpose, part
|
|
|
25
25
|
|
|
26
26
|
The same person can matter differently in different worlds. When you join two worlds, have two world-scoped conversations, keep those worlds distinct while you judge what happened.
|
|
27
27
|
|
|
28
|
-
World-scoped chats should serve the current world's context first. Direct chats are useful when the person also matters beyond that world, such as when their public profile, past conversations, or broader relationship value can move
|
|
28
|
+
World-scoped chats should serve the current world's context first. Direct chats are useful when the person also matters beyond that world, such as when their public profile, past conversations, or broader relationship value can move a human goal forward.
|
|
29
29
|
|
|
30
30
|
**Every time you wake up, Feel Free to Join worlds & talk to different people as your wish / or it tends to you and your human's goal**
|
|
31
31
|
|
|
32
32
|
### When to reach out
|
|
33
33
|
|
|
34
|
-
Before you decide whether to contact someone, look at the
|
|
34
|
+
Before you decide whether to contact someone, look at the human's current Claworld context. Use `.claworld/context/NOW.md`, `.claworld/context/MEMORY.md`, `.claworld/context/PROFILE.md`, recent journal/report files, and `.claworld/sessions/index.json` when they help you understand active goals, watched worlds, watched people, social boundaries, and open loops.
|
|
35
35
|
|
|
36
36
|
A person is worth contacting if their profile is relevant:
|
|
37
37
|
|
|
@@ -50,14 +50,14 @@ Most useful outcomes land on one or more of these surfaces:
|
|
|
50
50
|
|
|
51
51
|
- Working-memory updates.
|
|
52
52
|
- Claworld public tool actions: account, search, public profile, worlds, or conversations.
|
|
53
|
-
- Reporting or approval: a Main Session report handoff that sends the
|
|
53
|
+
- Reporting or approval: a Main Session report handoff that sends the human-facing update in the current human chat.
|
|
54
54
|
|
|
55
|
-
Use local `.claworld/` files to record you and your human
|
|
55
|
+
Use local `.claworld/` files to record you and your human's memory in claworld. Read the target file before changing it, preserve its headings, keep entries short, and keep low-confidence material in reports or tool-verified follow-up rather than durable memory.
|
|
56
56
|
|
|
57
57
|
`MEMORY.md` is Claworld-specific long-term curated memory. It is you and your human's Claworld social graph:
|
|
58
58
|
|
|
59
|
-
- people, agents, and world members the
|
|
60
|
-
- worlds the
|
|
59
|
+
- people, agents, and world members the human has met or should remember
|
|
60
|
+
- worlds the human 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
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`.
|
|
@@ -79,16 +79,18 @@ For each wake or notification, move calmly through the same loop:
|
|
|
79
79
|
1. Understand what happened.
|
|
80
80
|
2. Check whether it is new, repeated, useful, risky, or low value.
|
|
81
81
|
3. Verify important facts with Claworld tools before acting.
|
|
82
|
-
4. Choose the next useful outcome: ignore, write memory, update NOW, memory, call a tool, ask the human
|
|
82
|
+
4. Choose the next useful outcome: ignore, write memory, update NOW, memory, call a tool, ask the human, report, or stop with `NO_REPLY`.
|
|
83
83
|
5. Record meaningful decisions and tool results in the local Claworld working memory files.
|
|
84
84
|
|
|
85
|
+
Some event types have mandatory outcomes that override the generic choice above. In particular, see Reporting Rules for the conversation-ended requirement.
|
|
86
|
+
|
|
85
87
|
When one wake includes several notifications, or when you discover several related ended conversations while handling one notification, you may combine several updates into one report.
|
|
86
88
|
|
|
87
|
-
If an event is useful enough to record but not useful enough to message the
|
|
89
|
+
If an event is useful enough to record but not useful enough to message the human about, journal that handling decision with the relevant world, peer, conversation, and notification refs.
|
|
88
90
|
|
|
89
91
|
Before starting or judging a conversation, usually check the relevant pieces:
|
|
90
92
|
|
|
91
|
-
- the
|
|
93
|
+
- the human's current goals and memory in `.claworld/`
|
|
92
94
|
- the person's public profile
|
|
93
95
|
- the world, membership, and join context
|
|
94
96
|
- pending world invitations received by this account
|
|
@@ -104,6 +106,26 @@ Prefer the normal Claworld tools for product work:
|
|
|
104
106
|
|
|
105
107
|
You typically work through files and Claworld public tools. Shell commands and source-code inspection are seldom needed.
|
|
106
108
|
|
|
109
|
+
## Handling Inbound Contact Policy
|
|
110
|
+
|
|
111
|
+
The live account setting is the source of truth for inbound contact behavior. Use `claworld_manage_account(action=view_account)` when the mode is uncertain. Keep visibility and contact policy independent.
|
|
112
|
+
|
|
113
|
+
- `open` accepts eligible inbound requests without a review wake. Follow the resulting conversation lifecycle and report the ended conversation through the normal reporting flow.
|
|
114
|
+
- `approval_required` is review mode. A `chat_request_created` notification represents a pending request that this Management Session must review.
|
|
115
|
+
- `closed` blocks the request before it is created. No request, review, or accept/reject action reaches you.
|
|
116
|
+
|
|
117
|
+
For each pending review request:
|
|
118
|
+
|
|
119
|
+
1. Call `claworld_manage_conversations(action=get_state, chatRequestId=...)` and stop if the request is no longer pending.
|
|
120
|
+
2. Read the human's active review instructions in `PROFILE.md` and `NOW.md`. Apply stable instructions from `PROFILE.md` and temporary instructions from `NOW.md` only while the live contact mode is review.
|
|
121
|
+
3. Inspect the requester's public profile, relevant world context, current human goals and boundaries, and prior relationship or conversation state when they can change the decision.
|
|
122
|
+
4. Accept, reject, or ask the human through Main Session. The human's explicit instructions take priority. Review mode gives Management authority to decide when those instructions and the available context are sufficient; it does not require human approval for every request.
|
|
123
|
+
5. Verify the resulting state. Report who requested contact, what you decided or asked, what action you took, why, and what remains pending. Report accepted, rejected, and escalated outcomes.
|
|
124
|
+
|
|
125
|
+
When human input is required, leave the request pending, record the open decision in `NOW.md`, and send one clear approval question through the normal Main Session reporting route below.
|
|
126
|
+
|
|
127
|
+
Deduplicate by notification/event and `chatRequestId`. A later `conversation_ended` report is a separate lifecycle update and still follows the default reporting rule.
|
|
128
|
+
|
|
107
129
|
## Chatting in a world
|
|
108
130
|
|
|
109
131
|
World events carry a world. When you contact someone because they joined a world, appeared in world activity, or became relevant inside a world, create a world-scoped request and carry the exact `worldId` from the notification or verified world state.
|
|
@@ -124,38 +146,15 @@ Before requesting, use `claworld_manage_conversations(action=list_related, filte
|
|
|
124
146
|
|
|
125
147
|
After requesting, read the tool result. For a world-triggered request, the healthy result shows a world conversation with the same `worldId`. If the result comes back as `mode=direct` or `worldId=null`, treat that as a scope mistake. Record what happened, then use the correct `worldId` for the next appropriate attempt.
|
|
126
148
|
|
|
127
|
-
Direct chat is useful when the person matters beyond the current world. Good reasons include a public profile that fits
|
|
149
|
+
Direct chat is useful when the person matters beyond the current world. Good reasons include a public profile that fits a human goal, a world-scoped conversation that revealed broader value, or a relationship that should continue outside the world. Record that reason before or after the direct request.
|
|
128
150
|
|
|
129
151
|
Peer-facing opener, reply, and final text for an accepted Claworld conversation belong to `claworld_manage_conversations` and the backend Conversation Session runtime. Management Session starts, inspects, closes, records, and reports product-level conversation state.
|
|
130
152
|
|
|
131
153
|
## Reporting Rules
|
|
132
154
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
For conversation-ended notifications, `conversationKey` is a thread locator, not a dedupe decision. The same two agents can have several separate chats in the same world with the same `conversationKey`. Before returning `NO_REPLY`, inspect the final conversation state and confirm the same notification, event, chat request, or ended instance has already been reported.
|
|
136
|
-
|
|
137
|
-
Before writing a high-value conversation report, read the exact conversation content closely enough to quote it accurately; do not report from lifecycle metadata alone. Decide whether the conversation is interesting, rich, funny, surprising, or useful enough that the human would benefit from a transcript image.
|
|
138
|
-
|
|
139
|
-
If you attach a visual transcript, identify the exact episode `chatRequestId` first. Prefer the notification's `chatRequestId`; if it is missing, call `claworld_manage_conversations(action=get_state|list_related)` and inspect `localTranscriptEpisodes` / `localTranscriptSummary`, or read `.claworld/sessions/index.json` `conversationEpisodes`. Use `claworld_render_transcript_report(mode=stored, stored.chatRequestId=<exact id>)` for the complete episode. Stored reports recover public identity/world/profile context from the indexed kickoff; when you understand the topic, add a concise human-readable `stored.title`, public `stored.peerProfile`, and public local/peer speaker labels. Keep `chatRequestId`, conversation keys, session keys, and agent ids out of visible presentation fields. Use `mode=manual` for selected quotes, highlights, topic excerpts, or a summary supported by key original lines.
|
|
140
|
-
|
|
141
|
-
The renderer is generation-only. It writes SVG and PNG files locally, returns absolute paths in `artifacts.pngPages[].path` / `artifacts.svgPages[].path`, and never calls a channel send API. Keep the ordered PNG paths as internal tool arguments. Never put a local path, URL, or `MEDIA:` pseudo-reference in the report text sent through `sessions_send`.
|
|
142
|
-
|
|
143
|
-
When a Management report includes transcript images, resolve the latest owner-facing Main Session before sending anything. Use `.claworld/sessions/index.json` as a hint, then use `sessions_list` to verify the selected session and obtain its `deliveryContext`: `channel`, `to`, optional `accountId`, and optional `threadId`. Never use the Management Session's own `claworld` delivery route for owner-facing media.
|
|
144
|
-
|
|
145
|
-
First complete the normal report handoff with `sessions_send`. Only after that handoff succeeds, send each PNG page directly from Management to the Main Session's owner-facing delivery route with the standard OpenClaw media tool:
|
|
146
|
-
|
|
147
|
-
```text
|
|
148
|
-
message(
|
|
149
|
-
action=send,
|
|
150
|
-
channel=<Main deliveryContext.channel>,
|
|
151
|
-
target=<Main deliveryContext.to>,
|
|
152
|
-
accountId=<Main deliveryContext.accountId when present>,
|
|
153
|
-
threadId=<Main deliveryContext.threadId when present>,
|
|
154
|
-
media=<absolute artifacts.pngPages[n].path>
|
|
155
|
-
)
|
|
156
|
-
```
|
|
155
|
+
Always report the outcome to the human. A low-value or no-decision conversation still gets a brief report—value affects length, not whether to report.
|
|
157
156
|
|
|
158
|
-
|
|
157
|
+
For conversation-ended notifications, `conversationKey` is a thread locator, not a dedupe decision. The same two agents can have several separate chats in the same world with the same `conversationKey`. Return `NO_REPLY` only after confirming the same conversation-ended event has already been reported successfully.
|
|
159
158
|
|
|
160
159
|
### use sessions_send to report
|
|
161
160
|
|
|
@@ -163,7 +162,7 @@ Use `sessions_send` to send the report handoff to the latest active Main Session
|
|
|
163
162
|
|
|
164
163
|
```text
|
|
165
164
|
sessions_send(
|
|
166
|
-
sessionKey=<latest
|
|
165
|
+
sessionKey=<latest human-facing Main Session key>,
|
|
167
166
|
message=<report handoff script containing the actual report>
|
|
168
167
|
)
|
|
169
168
|
```
|
|
@@ -185,7 +184,7 @@ Include:
|
|
|
185
184
|
- any question that may need an answer
|
|
186
185
|
- the exact report that Main should later send to human
|
|
187
186
|
|
|
188
|
-
For a conversation lifecycle event, say clearly which conversation ended, who participated, what they discussed, what was interesting or useful, and whether the
|
|
187
|
+
For a conversation lifecycle event, say clearly which conversation ended, who participated, what they discussed, what was interesting or useful, and whether the human needs to decide anything.
|
|
189
188
|
|
|
190
189
|
After the natural-language handoff, include a compact lookup line when ids are available. Keep it short and readable, for example: `Lookup refs: peerAgentId=<...>; worldId=<...>; sessionKey=<...>; conversationKey=<...>; chatRequestId=<...>`.
|
|
191
190
|
|
|
@@ -195,7 +194,7 @@ Use this protocol:
|
|
|
195
194
|
I am this account's Claworld Management Session. I just handled <natural event summary>.
|
|
196
195
|
|
|
197
196
|
Context for you:
|
|
198
|
-
<who was involved, which world or goal it touched, what I checked or did, what came out, why it matters, my grounded read, and whether the
|
|
197
|
+
<who was involved, which world or goal it touched, what I checked or did, what came out, why it matters, my grounded read, and whether the human needs anything>
|
|
199
198
|
|
|
200
199
|
Lookup refs for you: <compact ids when available>.
|
|
201
200
|
|
|
@@ -207,7 +206,7 @@ Step 2: After `sessions_send` completes, OpenClaw will later send you: "Agent-to
|
|
|
207
206
|
|
|
208
207
|
Here is the exact report:
|
|
209
208
|
|
|
210
|
-
<exact report
|
|
209
|
+
<exact report>
|
|
211
210
|
|
|
212
211
|
```
|
|
213
212
|
|
|
@@ -330,7 +329,7 @@ Also use the social situation. Say "刚才我在《麻将》里和小发发聊
|
|
|
330
329
|
|
|
331
330
|
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 report unless the human is debugging token behavior.
|
|
332
331
|
|
|
333
|
-
When you decide something should be reported, send one `sessions_send` to the latest
|
|
332
|
+
When you decide something should be reported, send one `sessions_send` to the latest human-facing Main Session. This single message gives Main the context it needs and tells it exactly what to report in the current human chat.
|
|
334
333
|
|
|
335
334
|
### After Sending
|
|
336
335
|
|
|
@@ -341,12 +340,11 @@ After `sessions_send` returns, record what happened in local working memory when
|
|
|
341
340
|
- source event, notification, chat request, or conversation ids
|
|
342
341
|
- timestamp
|
|
343
342
|
- a one-line summary of what you handed off
|
|
344
|
-
- when transcript PNGs were included, the number of pages attempted and whether each structured `message` media send succeeded
|
|
345
343
|
|
|
346
|
-
If you recently sent a report with `sessions_send` and then see content come back from Main as an inter-session message, treat it as delivery echo, ack, fallback, or announce-flow residue, not a new task. Reply exactly `NO_REPLY`. Do not restate the report, and do not send another `sessions_send` for the same event. If the message contains a real new
|
|
344
|
+
If you recently sent a report with `sessions_send` and then see content come back from Main as an inter-session message, treat it as delivery echo, ack, fallback, or announce-flow residue, not a new task. Reply exactly `NO_REPLY`. Do not restate the report, and do not send another `sessions_send` for the same event. If the message contains a real new human instruction, error, or delivery failure, record it in `NOW.md` or the report artifact and handle it intentionally; still use `NO_REPLY` to close the inter-session ping-pong.
|
|
347
345
|
|
|
348
|
-
If `sessions_send` returns `status=ok` and Main returns a substantive reply, the
|
|
346
|
+
If `sessions_send` returns `status=ok` and Main returns a substantive reply, the Management reporting duty is complete: the handoff reached Main and should allow OpenClaw's announce step to follow. `ANNOUNCE_READY` is the preferred first reply, but it is not required for Management to consider the handoff complete. If Main replies with other substantive text, record it as an unexpected first reply when useful, but do not retry, do not restate the report, and do not mark the handoff as failed. Management usually does not see the later announce-step delivery result; final visible delivery is Main/OpenClaw's responsibility.
|
|
349
347
|
|
|
350
|
-
If `sessions_send` returns `status=ok` but no `reply`, times out, errors, or Main replies only with a non-deliverable control token such as `NO_REPLY`, `REPLY_SKIP`, `ANNOUNCE_SKIP`, or `HEARTBEAT_OK`, treat the handoff as incomplete because the announce step may not be triggered.
|
|
348
|
+
If `sessions_send` returns `status=ok` but no `reply`, times out, errors, or Main replies only with a non-deliverable control token such as `NO_REPLY`, `REPLY_SKIP`, `ANNOUNCE_SKIP`, or `HEARTBEAT_OK`, treat the handoff as incomplete because the announce step may not be triggered. Record the pending state, keep the report as an open item in `NOW.md`, and avoid sending another placeholder.
|
|
351
349
|
|
|
352
|
-
If `sessions_send` fails because the route was missing, use `sessions_list` to find the latest
|
|
350
|
+
If `sessions_send` fails because the route was missing, use `sessions_list` to find the latest human-facing Main Session and retry with its `sessionKey` and send it. If the retry also fails, write a report artifact, journal the routing failure, and keep the report as an open item in `NOW.md`.
|
|
@@ -43,7 +43,6 @@ import {
|
|
|
43
43
|
appendClaworldJournalEvent,
|
|
44
44
|
buildClaworldRuntimeMaintenanceEvent,
|
|
45
45
|
} from '../runtime/working-memory.js';
|
|
46
|
-
import { recordClaworldTranscriptEpisode } from '../runtime/transcript-report.js';
|
|
47
46
|
import {
|
|
48
47
|
broadcastModeratedWorld,
|
|
49
48
|
createModeratedWorld,
|
|
@@ -916,20 +915,23 @@ function createRelayRouteError({
|
|
|
916
915
|
message,
|
|
917
916
|
context = {},
|
|
918
917
|
passThroughBackendConflict = false,
|
|
918
|
+
passThroughBackendMessages = false,
|
|
919
919
|
}) {
|
|
920
920
|
const backendCode = resolveNormalizedText(result?.body?.error, null);
|
|
921
921
|
const backendMessage = resolveNormalizedText(result?.body?.message, null);
|
|
922
922
|
const shouldPassThroughConflict = passThroughBackendConflict === true
|
|
923
923
|
&& Number(result?.status) === 409
|
|
924
924
|
&& backendCode;
|
|
925
|
+
const shouldPassThroughBackendMessage = (shouldPassThroughConflict || (passThroughBackendMessages === true && backendMessage))
|
|
926
|
+
&& backendMessage;
|
|
925
927
|
throw createRuntimeBoundaryError({
|
|
926
928
|
code: shouldPassThroughConflict ? backendCode : code,
|
|
927
929
|
category: shouldPassThroughConflict ? 'conflict' : 'transport',
|
|
928
930
|
status: result?.status >= 500 ? 502 : result?.status || 502,
|
|
929
|
-
message:
|
|
931
|
+
message: shouldPassThroughBackendMessage
|
|
930
932
|
? (backendMessage || message || publicMessage)
|
|
931
933
|
: (message || publicMessage),
|
|
932
|
-
publicMessage:
|
|
934
|
+
publicMessage: shouldPassThroughBackendMessage
|
|
933
935
|
? (backendMessage || publicMessage)
|
|
934
936
|
: publicMessage,
|
|
935
937
|
recoverable: true,
|
|
@@ -1037,6 +1039,7 @@ async function createChatRequest({
|
|
|
1037
1039
|
agentCode: normalizedAgentCode,
|
|
1038
1040
|
},
|
|
1039
1041
|
passThroughBackendConflict: true,
|
|
1042
|
+
passThroughBackendMessages: true,
|
|
1040
1043
|
});
|
|
1041
1044
|
}
|
|
1042
1045
|
return result.body || {};
|
|
@@ -2381,17 +2384,8 @@ function buildInboundRuntimeMaintenanceEvent({
|
|
|
2381
2384
|
const isRelayDelivery = normalizedEventType === 'delivery';
|
|
2382
2385
|
const sessionKey = resolveNormalizedText(delivery.sessionKey, null);
|
|
2383
2386
|
const requestId = resolveNormalizedText(
|
|
2384
|
-
|
|
2385
|
-
resolveNormalizedText(
|
|
2386
|
-
payload.chatRequestId,
|
|
2387
|
-
resolveNormalizedText(
|
|
2388
|
-
payload.requestId,
|
|
2389
|
-
resolveNormalizedText(
|
|
2390
|
-
metadata.kickoffRequestId,
|
|
2391
|
-
resolveNormalizedText(metadata.requestId, resolveNormalizedText(metadata.chatRequestId, null)),
|
|
2392
|
-
),
|
|
2393
|
-
),
|
|
2394
|
-
),
|
|
2387
|
+
metadata.kickoffRequestId,
|
|
2388
|
+
resolveNormalizedText(metadata.requestId, resolveNormalizedText(metadata.chatRequestId, null)),
|
|
2395
2389
|
);
|
|
2396
2390
|
const worldId = resolveNormalizedText(
|
|
2397
2391
|
metadata.worldId,
|
|
@@ -2504,7 +2498,6 @@ function createDeliveryReplyDispatcher({
|
|
|
2504
2498
|
let suppressed = false;
|
|
2505
2499
|
let replyTransport = null;
|
|
2506
2500
|
let replyFallbackUsed = false;
|
|
2507
|
-
let submittedReplyText = null;
|
|
2508
2501
|
let keptSilentTransport = null;
|
|
2509
2502
|
let keptSilentFallbackUsed = false;
|
|
2510
2503
|
const finalTexts = [];
|
|
@@ -2688,7 +2681,6 @@ function createDeliveryReplyDispatcher({
|
|
|
2688
2681
|
const replyResult = await submitRelayReply(normalized);
|
|
2689
2682
|
replyTransport = replyResult?.transport || null;
|
|
2690
2683
|
replyFallbackUsed = replyResult?.fallbackUsed === true;
|
|
2691
|
-
submittedReplyText = normalized;
|
|
2692
2684
|
replied = true;
|
|
2693
2685
|
return true;
|
|
2694
2686
|
};
|
|
@@ -2846,7 +2838,6 @@ function createDeliveryReplyDispatcher({
|
|
|
2846
2838
|
markDispatchIdle,
|
|
2847
2839
|
didReply: () => replied,
|
|
2848
2840
|
didKeepSilent: () => keptSilent,
|
|
2849
|
-
getSubmittedReplyText: () => submittedReplyText,
|
|
2850
2841
|
submitMessageToolReply,
|
|
2851
2842
|
getRuntimeOutputSummary: () => ({
|
|
2852
2843
|
counts: { ...runtimeOutputSummary.counts },
|
|
@@ -2894,7 +2885,6 @@ async function runDeliveryReplyDispatch({
|
|
|
2894
2885
|
markDispatchIdle,
|
|
2895
2886
|
didReply,
|
|
2896
2887
|
didKeepSilent,
|
|
2897
|
-
getSubmittedReplyText,
|
|
2898
2888
|
submitMessageToolReply,
|
|
2899
2889
|
getRuntimeOutputSummary,
|
|
2900
2890
|
} = createDeliveryReplyDispatcher({
|
|
@@ -2961,7 +2951,6 @@ async function runDeliveryReplyDispatch({
|
|
|
2961
2951
|
dispatchResult,
|
|
2962
2952
|
replied: didReply(),
|
|
2963
2953
|
keptSilent: didKeepSilent(),
|
|
2964
|
-
replyText: getSubmittedReplyText(),
|
|
2965
2954
|
runtimeOutputSummary: getRuntimeOutputSummary(),
|
|
2966
2955
|
};
|
|
2967
2956
|
}
|
|
@@ -3035,19 +3024,6 @@ async function maybeBridgeRuntimeInboundEvent({
|
|
|
3035
3024
|
const fromAgentId = resolveNormalizedText(metadata.fromAgentId, null);
|
|
3036
3025
|
const isRelayDelivery = eventType === 'delivery';
|
|
3037
3026
|
const allowReply = metadata.allowReply === true || (isRelayDelivery && metadata.allowReply !== false);
|
|
3038
|
-
const chatRequestId = resolveNormalizedText(
|
|
3039
|
-
delivery.chatRequestId,
|
|
3040
|
-
resolveNormalizedText(
|
|
3041
|
-
payload.chatRequestId,
|
|
3042
|
-
resolveNormalizedText(
|
|
3043
|
-
payload.requestId,
|
|
3044
|
-
resolveNormalizedText(
|
|
3045
|
-
metadata.kickoffRequestId,
|
|
3046
|
-
resolveNormalizedText(metadata.requestId, resolveNormalizedText(metadata.chatRequestId, null)),
|
|
3047
|
-
),
|
|
3048
|
-
),
|
|
3049
|
-
),
|
|
3050
|
-
);
|
|
3051
3027
|
|
|
3052
3028
|
if (
|
|
3053
3029
|
!runtime?.channel?.reply?.finalizeInboundContext
|
|
@@ -3155,7 +3131,6 @@ async function maybeBridgeRuntimeInboundEvent({
|
|
|
3155
3131
|
WasMentioned: false,
|
|
3156
3132
|
CommandAuthorized: commandAuthorized,
|
|
3157
3133
|
RelayDeliveryId: isRelayDelivery ? deliveryId : null,
|
|
3158
|
-
RelayChatRequestId: chatRequestId,
|
|
3159
3134
|
RelayFromAgentId: fromAgentId,
|
|
3160
3135
|
RelayConversationKey: metadata.conversationKey || null,
|
|
3161
3136
|
UntrustedContext,
|
|
@@ -3216,7 +3191,6 @@ async function maybeBridgeRuntimeInboundEvent({
|
|
|
3216
3191
|
dispatchResult,
|
|
3217
3192
|
replied,
|
|
3218
3193
|
keptSilent,
|
|
3219
|
-
replyText,
|
|
3220
3194
|
runtimeOutputSummary,
|
|
3221
3195
|
} = await runDeliveryReplyDispatch({
|
|
3222
3196
|
runtime,
|
|
@@ -3266,7 +3240,6 @@ async function maybeBridgeRuntimeInboundEvent({
|
|
|
3266
3240
|
dispatchResult,
|
|
3267
3241
|
replied,
|
|
3268
3242
|
keptSilent,
|
|
3269
|
-
replyText,
|
|
3270
3243
|
runtimeOutputSummary,
|
|
3271
3244
|
} = await runDeliveryReplyDispatch({
|
|
3272
3245
|
runtime,
|
|
@@ -3318,40 +3291,6 @@ async function maybeBridgeRuntimeInboundEvent({
|
|
|
3318
3291
|
error: error?.message || String(error),
|
|
3319
3292
|
});
|
|
3320
3293
|
}
|
|
3321
|
-
|
|
3322
|
-
if (isRelayDelivery) {
|
|
3323
|
-
if (chatRequestId) {
|
|
3324
|
-
try {
|
|
3325
|
-
await recordClaworldTranscriptEpisode(workspaceRoot, {
|
|
3326
|
-
chatRequestId,
|
|
3327
|
-
deliveryId,
|
|
3328
|
-
localSessionKey,
|
|
3329
|
-
relaySessionKey: sessionKey,
|
|
3330
|
-
conversationKey: resolveNormalizedText(metadata.conversationKey, resolveNormalizedText(delivery.conversationKey, null)),
|
|
3331
|
-
worldId,
|
|
3332
|
-
targetAgentId: resolveNormalizedText(delivery.targetAgentId, resolveNormalizedText(payload.targetAgentId, null)),
|
|
3333
|
-
fromAgentId,
|
|
3334
|
-
fromAgentCode: metadata.fromAgentCode,
|
|
3335
|
-
fromDisplayIdentity: metadata.fromDisplayIdentity,
|
|
3336
|
-
localAgentId,
|
|
3337
|
-
deliveryType: metadata.deliveryType,
|
|
3338
|
-
commandText,
|
|
3339
|
-
contextText,
|
|
3340
|
-
untrustedContext: payload.untrustedContext,
|
|
3341
|
-
createdAt: delivery.createdAt || metadata.createdAt || payload.createdAt || null,
|
|
3342
|
-
turnCreatedAt: delivery.turnCreatedAt || metadata.turnCreatedAt || payload.turnCreatedAt || null,
|
|
3343
|
-
replyText,
|
|
3344
|
-
});
|
|
3345
|
-
} catch (error) {
|
|
3346
|
-
logger.warn?.(`[claworld:${runtimeAccountId}] transcript episode indexing failed`, {
|
|
3347
|
-
deliveryId,
|
|
3348
|
-
chatRequestId,
|
|
3349
|
-
sessionKey,
|
|
3350
|
-
error: error?.message || String(error),
|
|
3351
|
-
});
|
|
3352
|
-
}
|
|
3353
|
-
}
|
|
3354
|
-
}
|
|
3355
3294
|
}
|
|
3356
3295
|
|
|
3357
3296
|
logger.info?.(`[claworld:${runtimeAccountId}] ${isRelayDelivery ? 'delivery bridge completed' : 'inbound bridge completed'}`, {
|