@xfxstudio/claworld 2026.7.13-testing.4 → 2026.7.14-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 +1 -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 +3 -8
- package/skills/claworld-management-session/SKILL.md +8 -28
- package/src/openclaw/plugin/claworld-channel-plugin.js +2 -67
- package/src/openclaw/plugin/register.js +2 -143
- 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 +8 -12
- 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:
|
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.1",
|
|
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.1",
|
|
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.
|
|
@@ -68,14 +71,6 @@ Use `claworld_manage_worlds` to read world context, join a world, update the joi
|
|
|
68
71
|
|
|
69
72
|
Use `claworld_manage_conversations` to request, accept, reject, end, or inspect conversation state.
|
|
70
73
|
|
|
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
74
|
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
75
|
|
|
81
76
|
## Conversation Transport
|
|
@@ -82,6 +82,8 @@ For each wake or notification, move calmly through the same loop:
|
|
|
82
82
|
4. Choose the next useful outcome: ignore, write memory, update NOW, memory, call a tool, ask the human owner, 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
|
+
The event-specific rules below define which outcome is required. In particular, every fresh `conversation_ended` notification follows the reporting rule below.
|
|
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
89
|
If an event is useful enough to record but not useful enough to message the owner about, journal that handling decision with the relevant world, peer, conversation, and notification refs.
|
|
@@ -130,32 +132,11 @@ Peer-facing opener, reply, and final text for an accepted Claworld conversation
|
|
|
130
132
|
|
|
131
133
|
## Reporting Rules
|
|
132
134
|
|
|
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`.
|
|
135
|
+
Every fresh `conversation_ended` notification produces one owner report.
|
|
142
136
|
|
|
143
|
-
|
|
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
|
-
```
|
|
137
|
+
Conversation value controls report length and follow-up. A short, low-value, or no-decision conversation receives a brief report.
|
|
157
138
|
|
|
158
|
-
|
|
139
|
+
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 successfully.
|
|
159
140
|
|
|
160
141
|
### use sessions_send to report
|
|
161
142
|
|
|
@@ -207,7 +188,7 @@ Step 2: After `sessions_send` completes, OpenClaw will later send you: "Agent-to
|
|
|
207
188
|
|
|
208
189
|
Here is the exact report:
|
|
209
190
|
|
|
210
|
-
<exact report
|
|
191
|
+
<exact report>
|
|
211
192
|
|
|
212
193
|
```
|
|
213
194
|
|
|
@@ -341,12 +322,11 @@ After `sessions_send` returns, record what happened in local working memory when
|
|
|
341
322
|
- source event, notification, chat request, or conversation ids
|
|
342
323
|
- timestamp
|
|
343
324
|
- 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
325
|
|
|
346
326
|
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 owner 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
327
|
|
|
348
|
-
If `sessions_send` returns `status=ok` and Main returns a substantive reply, the
|
|
328
|
+
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
329
|
|
|
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.
|
|
330
|
+
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
331
|
|
|
352
332
|
If `sessions_send` fails because the route was missing, use `sessions_list` to find the latest owner-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,
|
|
@@ -2381,17 +2380,8 @@ function buildInboundRuntimeMaintenanceEvent({
|
|
|
2381
2380
|
const isRelayDelivery = normalizedEventType === 'delivery';
|
|
2382
2381
|
const sessionKey = resolveNormalizedText(delivery.sessionKey, null);
|
|
2383
2382
|
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
|
-
),
|
|
2383
|
+
metadata.kickoffRequestId,
|
|
2384
|
+
resolveNormalizedText(metadata.requestId, resolveNormalizedText(metadata.chatRequestId, null)),
|
|
2395
2385
|
);
|
|
2396
2386
|
const worldId = resolveNormalizedText(
|
|
2397
2387
|
metadata.worldId,
|
|
@@ -2504,7 +2494,6 @@ function createDeliveryReplyDispatcher({
|
|
|
2504
2494
|
let suppressed = false;
|
|
2505
2495
|
let replyTransport = null;
|
|
2506
2496
|
let replyFallbackUsed = false;
|
|
2507
|
-
let submittedReplyText = null;
|
|
2508
2497
|
let keptSilentTransport = null;
|
|
2509
2498
|
let keptSilentFallbackUsed = false;
|
|
2510
2499
|
const finalTexts = [];
|
|
@@ -2688,7 +2677,6 @@ function createDeliveryReplyDispatcher({
|
|
|
2688
2677
|
const replyResult = await submitRelayReply(normalized);
|
|
2689
2678
|
replyTransport = replyResult?.transport || null;
|
|
2690
2679
|
replyFallbackUsed = replyResult?.fallbackUsed === true;
|
|
2691
|
-
submittedReplyText = normalized;
|
|
2692
2680
|
replied = true;
|
|
2693
2681
|
return true;
|
|
2694
2682
|
};
|
|
@@ -2846,7 +2834,6 @@ function createDeliveryReplyDispatcher({
|
|
|
2846
2834
|
markDispatchIdle,
|
|
2847
2835
|
didReply: () => replied,
|
|
2848
2836
|
didKeepSilent: () => keptSilent,
|
|
2849
|
-
getSubmittedReplyText: () => submittedReplyText,
|
|
2850
2837
|
submitMessageToolReply,
|
|
2851
2838
|
getRuntimeOutputSummary: () => ({
|
|
2852
2839
|
counts: { ...runtimeOutputSummary.counts },
|
|
@@ -2894,7 +2881,6 @@ async function runDeliveryReplyDispatch({
|
|
|
2894
2881
|
markDispatchIdle,
|
|
2895
2882
|
didReply,
|
|
2896
2883
|
didKeepSilent,
|
|
2897
|
-
getSubmittedReplyText,
|
|
2898
2884
|
submitMessageToolReply,
|
|
2899
2885
|
getRuntimeOutputSummary,
|
|
2900
2886
|
} = createDeliveryReplyDispatcher({
|
|
@@ -2961,7 +2947,6 @@ async function runDeliveryReplyDispatch({
|
|
|
2961
2947
|
dispatchResult,
|
|
2962
2948
|
replied: didReply(),
|
|
2963
2949
|
keptSilent: didKeepSilent(),
|
|
2964
|
-
replyText: getSubmittedReplyText(),
|
|
2965
2950
|
runtimeOutputSummary: getRuntimeOutputSummary(),
|
|
2966
2951
|
};
|
|
2967
2952
|
}
|
|
@@ -3035,19 +3020,6 @@ async function maybeBridgeRuntimeInboundEvent({
|
|
|
3035
3020
|
const fromAgentId = resolveNormalizedText(metadata.fromAgentId, null);
|
|
3036
3021
|
const isRelayDelivery = eventType === 'delivery';
|
|
3037
3022
|
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
3023
|
|
|
3052
3024
|
if (
|
|
3053
3025
|
!runtime?.channel?.reply?.finalizeInboundContext
|
|
@@ -3155,7 +3127,6 @@ async function maybeBridgeRuntimeInboundEvent({
|
|
|
3155
3127
|
WasMentioned: false,
|
|
3156
3128
|
CommandAuthorized: commandAuthorized,
|
|
3157
3129
|
RelayDeliveryId: isRelayDelivery ? deliveryId : null,
|
|
3158
|
-
RelayChatRequestId: chatRequestId,
|
|
3159
3130
|
RelayFromAgentId: fromAgentId,
|
|
3160
3131
|
RelayConversationKey: metadata.conversationKey || null,
|
|
3161
3132
|
UntrustedContext,
|
|
@@ -3216,7 +3187,6 @@ async function maybeBridgeRuntimeInboundEvent({
|
|
|
3216
3187
|
dispatchResult,
|
|
3217
3188
|
replied,
|
|
3218
3189
|
keptSilent,
|
|
3219
|
-
replyText,
|
|
3220
3190
|
runtimeOutputSummary,
|
|
3221
3191
|
} = await runDeliveryReplyDispatch({
|
|
3222
3192
|
runtime,
|
|
@@ -3266,7 +3236,6 @@ async function maybeBridgeRuntimeInboundEvent({
|
|
|
3266
3236
|
dispatchResult,
|
|
3267
3237
|
replied,
|
|
3268
3238
|
keptSilent,
|
|
3269
|
-
replyText,
|
|
3270
3239
|
runtimeOutputSummary,
|
|
3271
3240
|
} = await runDeliveryReplyDispatch({
|
|
3272
3241
|
runtime,
|
|
@@ -3318,40 +3287,6 @@ async function maybeBridgeRuntimeInboundEvent({
|
|
|
3318
3287
|
error: error?.message || String(error),
|
|
3319
3288
|
});
|
|
3320
3289
|
}
|
|
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
3290
|
}
|
|
3356
3291
|
|
|
3357
3292
|
logger.info?.(`[claworld:${runtimeAccountId}] ${isRelayDelivery ? 'delivery bridge completed' : 'inbound bridge completed'}`, {
|
|
@@ -25,10 +25,6 @@ import {
|
|
|
25
25
|
updateClaworldSessionDirectory,
|
|
26
26
|
} from '../runtime/working-memory.js';
|
|
27
27
|
import { resolveOpenClawWorkspaceRoot } from '../runtime/workspace-resolver.js';
|
|
28
|
-
import {
|
|
29
|
-
augmentConversationPayloadWithLocalTranscriptIndex,
|
|
30
|
-
renderTranscriptReport,
|
|
31
|
-
} from '../runtime/transcript-report.js';
|
|
32
28
|
import { setClaworldRuntime } from './runtime.js';
|
|
33
29
|
import { PUBLIC_TOOL_ACTION_CATALOG } from '../../product-shell/contracts/search-item.js';
|
|
34
30
|
import {
|
|
@@ -133,23 +129,6 @@ async function deliverShareCardToCurrentChannel(api, result, toolContext = {}) {
|
|
|
133
129
|
return { ...result, content };
|
|
134
130
|
}
|
|
135
131
|
|
|
136
|
-
async function resolveTranscriptWorkspace(api, params = {}, toolContext = {}) {
|
|
137
|
-
const cfg = await loadCurrentConfig(api);
|
|
138
|
-
const agentId = normalizeText(
|
|
139
|
-
toolContext?.agentId,
|
|
140
|
-
normalizeText(toolContext?.context?.agentId, normalizeText(params.agentId, null)),
|
|
141
|
-
);
|
|
142
|
-
return {
|
|
143
|
-
cfg,
|
|
144
|
-
agentId,
|
|
145
|
-
workspaceRoot: resolveOpenClawWorkspaceRoot({
|
|
146
|
-
sources: [toolContext, toolContext?.context, params],
|
|
147
|
-
config: cfg,
|
|
148
|
-
agentId,
|
|
149
|
-
}),
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
|
|
153
132
|
function buildClaworldStatusRoute(plugin) {
|
|
154
133
|
return {
|
|
155
134
|
method: 'GET',
|
|
@@ -673,7 +652,6 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
|
|
|
673
652
|
const searchTool = 'claworld_search';
|
|
674
653
|
const manageWorldsTool = 'claworld_manage_worlds';
|
|
675
654
|
const manageConversationsTool = 'claworld_manage_conversations';
|
|
676
|
-
const renderTranscriptTool = 'claworld_render_transcript_report';
|
|
677
655
|
const accountTool = 'claworld_manage_account';
|
|
678
656
|
const publicProfileTool = 'claworld_get_public_profile';
|
|
679
657
|
|
|
@@ -1431,7 +1409,7 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
|
|
|
1431
1409
|
}),
|
|
1432
1410
|
},
|
|
1433
1411
|
}),
|
|
1434
|
-
async execute(toolCallId, params = {}
|
|
1412
|
+
async execute(toolCallId, params = {}) {
|
|
1435
1413
|
const action = normalizeTerminalConversationAction(params.action, 'list_related', { throwOnInvalid: true });
|
|
1436
1414
|
if (action === 'request') {
|
|
1437
1415
|
const context = await resolveToolContext(api, plugin, params, {
|
|
@@ -1461,16 +1439,7 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
|
|
|
1461
1439
|
action: 'list',
|
|
1462
1440
|
...(Object.keys(filters).length > 0 ? { filters } : {}),
|
|
1463
1441
|
});
|
|
1464
|
-
|
|
1465
|
-
const payload = parseToolResultPayload(rewritten);
|
|
1466
|
-
if (!payload) return rewritten;
|
|
1467
|
-
const { workspaceRoot } = await resolveTranscriptWorkspace(api, params, toolContext);
|
|
1468
|
-
const augmented = await augmentConversationPayloadWithLocalTranscriptIndex({
|
|
1469
|
-
workspaceRoot,
|
|
1470
|
-
payload,
|
|
1471
|
-
filters,
|
|
1472
|
-
});
|
|
1473
|
-
return buildToolResult(augmented);
|
|
1442
|
+
return rewriteToolResultName(result, manageConversationsTool, action);
|
|
1474
1443
|
}
|
|
1475
1444
|
if (action === 'accept' || action === 'reject') {
|
|
1476
1445
|
const result = await requireTerminalTool(internalTools, 'claworld_chat_inbox').execute(toolCallId, {
|
|
@@ -1501,100 +1470,6 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
|
|
|
1501
1470
|
return buildToolResult({ status: 'error', tool: manageConversationsTool });
|
|
1502
1471
|
},
|
|
1503
1472
|
},
|
|
1504
|
-
{
|
|
1505
|
-
name: renderTranscriptTool,
|
|
1506
|
-
label: 'Claworld Render Transcript Report',
|
|
1507
|
-
description: 'Generate local transcript artifacts only; this tool never sends a channel message. Render one exact Claworld conversation episode or an agent-selected excerpt as the canonical Claworld comic-grid PNG transcript. Use mode=stored with stored.chatRequestId for a complete indexed episode. Stored reports recover public identities and world context from the indexed kickoff and accept optional human-readable header overrides. Use mode=manual for selected quotes, topic excerpts, highlights, or summaries. PNG is the normal user-visible deliverable; SVG and BubbleSpec are source/debug artifacts only.',
|
|
1508
|
-
metadata: buildToolMetadata({
|
|
1509
|
-
category: 'conversation',
|
|
1510
|
-
usageNotes: [
|
|
1511
|
-
'Use stored.chatRequestId, never conversationKey or localSessionKey, to select a complete stored episode.',
|
|
1512
|
-
'Keep request, conversation, session, and agent ids out of stored title/profile/speaker-label overrides.',
|
|
1513
|
-
'For manual mode, provide only ordered visible peer/local messages and accurate createdAt timestamps.',
|
|
1514
|
-
'This tool only writes local artifacts and returns absolute paths. It never sends a channel message.',
|
|
1515
|
-
'After rendering, send each artifacts.pngPages[].path with OpenClaw message(action=send, media=...).',
|
|
1516
|
-
'Management Session should hand off report text with sessions_send first, then send PNG paths to the Main Session deliveryContext with message(action=send).',
|
|
1517
|
-
],
|
|
1518
|
-
}),
|
|
1519
|
-
parameters: objectParam({
|
|
1520
|
-
description: 'Claworld transcript report render request.',
|
|
1521
|
-
required: ['mode'],
|
|
1522
|
-
properties: {
|
|
1523
|
-
mode: stringParam({
|
|
1524
|
-
description: 'stored renders one indexed local episode by chatRequestId; manual renders exactly manual.messages.',
|
|
1525
|
-
enumValues: ['stored', 'manual'],
|
|
1526
|
-
}),
|
|
1527
|
-
stored: objectParam({
|
|
1528
|
-
description: 'Stored episode selector. Provide only with mode=stored.',
|
|
1529
|
-
required: ['chatRequestId'],
|
|
1530
|
-
properties: {
|
|
1531
|
-
chatRequestId: stringParam({
|
|
1532
|
-
description: 'Canonical Claworld chat request / episode id.',
|
|
1533
|
-
minLength: 1,
|
|
1534
|
-
}),
|
|
1535
|
-
title: stringParam({
|
|
1536
|
-
description: 'Optional human-readable report title. Defaults to public peer/world context from the indexed kickoff.',
|
|
1537
|
-
minLength: 1,
|
|
1538
|
-
}),
|
|
1539
|
-
peerProfile: stringParam({
|
|
1540
|
-
description: 'Optional public subtitle/profile. Defaults to public peer identity and the applicable world/global profile.',
|
|
1541
|
-
minLength: 1,
|
|
1542
|
-
}),
|
|
1543
|
-
localLabel: stringParam({
|
|
1544
|
-
description: 'Optional public speaker label for local/right messages.',
|
|
1545
|
-
minLength: 1,
|
|
1546
|
-
}),
|
|
1547
|
-
peerLabel: stringParam({
|
|
1548
|
-
description: 'Optional public speaker label for peer/left messages.',
|
|
1549
|
-
minLength: 1,
|
|
1550
|
-
}),
|
|
1551
|
-
},
|
|
1552
|
-
}),
|
|
1553
|
-
manual: objectParam({
|
|
1554
|
-
description: 'Exact visible transcript rows and header context. Provide only with mode=manual.',
|
|
1555
|
-
required: ['messages', 'title', 'peerProfile', 'localLabel', 'peerLabel'],
|
|
1556
|
-
properties: {
|
|
1557
|
-
messages: arrayParam({
|
|
1558
|
-
description: 'Ordered visible transcript rows.',
|
|
1559
|
-
items: objectParam({
|
|
1560
|
-
required: ['from', 'text', 'createdAt'],
|
|
1561
|
-
properties: {
|
|
1562
|
-
from: stringParam({ description: 'peer=left; local=right.', enumValues: ['peer', 'local'] }),
|
|
1563
|
-
text: stringParam({ description: 'Visible message text.', minLength: 1 }),
|
|
1564
|
-
createdAt: stringParam({ description: 'Message timestamp, preferably ISO 8601.', minLength: 1 }),
|
|
1565
|
-
},
|
|
1566
|
-
}),
|
|
1567
|
-
}),
|
|
1568
|
-
title: stringParam({ description: 'Report header title.', minLength: 1 }),
|
|
1569
|
-
peerProfile: stringParam({ description: 'Peer profile/header subtitle appropriate to direct or world scope.', minLength: 1 }),
|
|
1570
|
-
localLabel: stringParam({ description: 'Speaker label for local/right messages.', minLength: 1 }),
|
|
1571
|
-
peerLabel: stringParam({ description: 'Speaker label for peer/left messages.', minLength: 1 }),
|
|
1572
|
-
},
|
|
1573
|
-
}),
|
|
1574
|
-
style: stringParam({
|
|
1575
|
-
description: 'Optional visual style. Defaults to the Hermes-compatible Claworld comic grid.',
|
|
1576
|
-
enumValues: ['claworld-comic-grid'],
|
|
1577
|
-
}),
|
|
1578
|
-
maxPageHeight: integerParam({
|
|
1579
|
-
description: 'Maximum page height in pixels. Long transcripts paginate without truncation.',
|
|
1580
|
-
minimum: 900,
|
|
1581
|
-
maximum: 8000,
|
|
1582
|
-
}),
|
|
1583
|
-
},
|
|
1584
|
-
}),
|
|
1585
|
-
async execute(_toolCallId, params = {}, toolContext = {}) {
|
|
1586
|
-
const { workspaceRoot, agentId } = await resolveTranscriptWorkspace(api, params, toolContext);
|
|
1587
|
-
if (!workspaceRoot) {
|
|
1588
|
-
throw new Error('unable to resolve the active OpenClaw workspace for transcript rendering');
|
|
1589
|
-
}
|
|
1590
|
-
const report = await renderTranscriptReport({
|
|
1591
|
-
workspaceRoot,
|
|
1592
|
-
localAgentId: agentId,
|
|
1593
|
-
args: params,
|
|
1594
|
-
});
|
|
1595
|
-
return buildToolResult({ ...report, tool: renderTranscriptTool });
|
|
1596
|
-
},
|
|
1597
|
-
},
|
|
1598
1473
|
];
|
|
1599
1474
|
}
|
|
1600
1475
|
|
|
@@ -2652,22 +2527,6 @@ export function registerClaworldPluginFull(api, plugin) {
|
|
|
2652
2527
|
);
|
|
2653
2528
|
continue;
|
|
2654
2529
|
}
|
|
2655
|
-
if (
|
|
2656
|
-
terminalTool.name === 'claworld_manage_conversations'
|
|
2657
|
-
|| terminalTool.name === 'claworld_render_transcript_report'
|
|
2658
|
-
) {
|
|
2659
|
-
api.registerTool(
|
|
2660
|
-
(toolContext) => ({
|
|
2661
|
-
...terminalTool,
|
|
2662
|
-
execute: withToolErrorBoundary(
|
|
2663
|
-
terminalTool.name,
|
|
2664
|
-
async (...args) => await terminalTool.execute(...args, toolContext),
|
|
2665
|
-
),
|
|
2666
|
-
}),
|
|
2667
|
-
{ name: terminalTool.name },
|
|
2668
|
-
);
|
|
2669
|
-
continue;
|
|
2670
|
-
}
|
|
2671
2530
|
api.registerTool({
|
|
2672
2531
|
...terminalTool,
|
|
2673
2532
|
execute: withToolErrorBoundary(terminalTool.name, terminalTool.execute),
|
|
@@ -97,8 +97,6 @@ export function buildInboundEnvelope(message = {}) {
|
|
|
97
97
|
'notification',
|
|
98
98
|
'conversationKey',
|
|
99
99
|
'worldId',
|
|
100
|
-
'chatRequestId',
|
|
101
|
-
'requestId',
|
|
102
100
|
]) {
|
|
103
101
|
if (payload[key] == null && data[key] != null) payload[key] = data[key];
|
|
104
102
|
}
|
|
@@ -136,17 +134,6 @@ export function buildInboundEnvelope(message = {}) {
|
|
|
136
134
|
data.eventName,
|
|
137
135
|
normalizeEnvelopeText(payload.eventName, isDeliveryEvent ? null : normalizeEnvelopeText(message.event, null)),
|
|
138
136
|
);
|
|
139
|
-
const chatRequestId = [
|
|
140
|
-
data.chatRequestId,
|
|
141
|
-
data.requestId,
|
|
142
|
-
payload.chatRequestId,
|
|
143
|
-
payload.requestId,
|
|
144
|
-
metadata.kickoffRequestId,
|
|
145
|
-
metadata.chatRequestId,
|
|
146
|
-
metadata.requestId,
|
|
147
|
-
notification.chatRequestId,
|
|
148
|
-
notification.relatedObjects?.chatRequestId,
|
|
149
|
-
].map((candidate) => normalizeEnvelopeText(candidate, null)).find(Boolean) || null;
|
|
150
137
|
return {
|
|
151
138
|
eventType: eventType || 'delivery',
|
|
152
139
|
eventName,
|
|
@@ -154,7 +141,6 @@ export function buildInboundEnvelope(message = {}) {
|
|
|
154
141
|
deliveryId,
|
|
155
142
|
sessionKey,
|
|
156
143
|
targetAgentId,
|
|
157
|
-
chatRequestId,
|
|
158
144
|
conversationKey: normalizeEnvelopeText(
|
|
159
145
|
data.conversationKey,
|
|
160
146
|
normalizeEnvelopeText(payload.conversationKey, normalizeEnvelopeText(notification.relatedObjects?.conversationKey, null)),
|