@xfxstudio/claworld 0.2.23-beta.0 → 0.2.23-beta.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/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/src/lib/chat-request.js +2 -1
- package/src/lib/relay/kickoff-progress.js +162 -0
- package/src/lib/relay/shared.js +30 -0
- package/src/openclaw/plugin/claworld-channel-plugin.js +115 -31
- package/src/openclaw/runtime/tool-contracts.js +14 -8
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
package/src/lib/chat-request.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createKickoffBrief } from './relay/kickoff-text.js';
|
|
2
|
+
import { normalizeAcceptedChatKickoffRecord } from './relay/kickoff-progress.js';
|
|
2
3
|
|
|
3
4
|
function normalizeText(value, fallback = null) {
|
|
4
5
|
if (value == null) return fallback;
|
|
@@ -358,7 +359,7 @@ export function normalizeStoredChatRequest(input = {}, { defaultSource = 'chat_r
|
|
|
358
359
|
if (acceptedByAgentId) normalized.acceptedByAgentId = acceptedByAgentId;
|
|
359
360
|
const approvalGrantId = normalizeText(input.approvalGrantId, null);
|
|
360
361
|
if (approvalGrantId) normalized.approvalGrantId = approvalGrantId;
|
|
361
|
-
const kickoff = cloneJsonObject(input.kickoff);
|
|
362
|
+
const kickoff = normalizeAcceptedChatKickoffRecord(cloneJsonObject(input.kickoff));
|
|
362
363
|
if (kickoff) normalized.kickoff = kickoff;
|
|
363
364
|
|
|
364
365
|
return normalized;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { normalizeOptionalText } from './shared.js';
|
|
2
|
+
|
|
3
|
+
function normalizeAcceptedChatKickoffField(value, fallback = null) {
|
|
4
|
+
return normalizeOptionalText(value) || fallback;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function normalizeAcceptedChatKickoffRecord(kickoff = null, { fallbackStatus = null } = {}) {
|
|
8
|
+
if (!kickoff || typeof kickoff !== 'object' || Array.isArray(kickoff)) return null;
|
|
9
|
+
|
|
10
|
+
const normalized = {
|
|
11
|
+
...kickoff,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const normalizedStatus = normalizeAcceptedChatKickoffField(normalized.status, fallbackStatus);
|
|
15
|
+
const normalizedReason = normalizeAcceptedChatKickoffField(normalized.reason, null);
|
|
16
|
+
const normalizedDeliveredAt = normalizeAcceptedChatKickoffField(normalized.deliveredAt, null);
|
|
17
|
+
const normalizedSenderKickoffDeliveredAt = normalizeAcceptedChatKickoffField(
|
|
18
|
+
normalized.senderKickoffDeliveredAt,
|
|
19
|
+
normalizedDeliveredAt,
|
|
20
|
+
);
|
|
21
|
+
const normalizedOpenerAcceptedAt = normalizeAcceptedChatKickoffField(normalized.openerAcceptedAt, null);
|
|
22
|
+
const normalizedOpenerDeliveredAt = normalizeAcceptedChatKickoffField(normalized.openerDeliveredAt, null);
|
|
23
|
+
const normalizedLiveChatEstablishedAt = normalizeAcceptedChatKickoffField(normalized.liveChatEstablishedAt, null);
|
|
24
|
+
const normalizedTurnId = normalizeAcceptedChatKickoffField(normalized.turnId, null);
|
|
25
|
+
const normalizedDeliveryId = normalizeAcceptedChatKickoffField(normalized.deliveryId, null);
|
|
26
|
+
const normalizedConversationKey = normalizeAcceptedChatKickoffField(normalized.conversationKey, null);
|
|
27
|
+
const normalizedOpenerTurnId = normalizeAcceptedChatKickoffField(normalized.openerTurnId, null);
|
|
28
|
+
const normalizedOpenerDeliveryId = normalizeAcceptedChatKickoffField(normalized.openerDeliveryId, null);
|
|
29
|
+
const normalizedFailedAt = normalizeAcceptedChatKickoffField(normalized.failedAt, null);
|
|
30
|
+
|
|
31
|
+
if (normalizedStatus) normalized.status = normalizedStatus;
|
|
32
|
+
else delete normalized.status;
|
|
33
|
+
if (normalizedReason) normalized.reason = normalizedReason;
|
|
34
|
+
else delete normalized.reason;
|
|
35
|
+
if (normalizedDeliveredAt) normalized.deliveredAt = normalizedDeliveredAt;
|
|
36
|
+
else delete normalized.deliveredAt;
|
|
37
|
+
if (normalizedSenderKickoffDeliveredAt) normalized.senderKickoffDeliveredAt = normalizedSenderKickoffDeliveredAt;
|
|
38
|
+
else delete normalized.senderKickoffDeliveredAt;
|
|
39
|
+
if (normalizedOpenerAcceptedAt) normalized.openerAcceptedAt = normalizedOpenerAcceptedAt;
|
|
40
|
+
else delete normalized.openerAcceptedAt;
|
|
41
|
+
if (normalizedOpenerDeliveredAt) normalized.openerDeliveredAt = normalizedOpenerDeliveredAt;
|
|
42
|
+
else delete normalized.openerDeliveredAt;
|
|
43
|
+
if (normalizedLiveChatEstablishedAt) normalized.liveChatEstablishedAt = normalizedLiveChatEstablishedAt;
|
|
44
|
+
else delete normalized.liveChatEstablishedAt;
|
|
45
|
+
if (normalizedTurnId) normalized.turnId = normalizedTurnId;
|
|
46
|
+
else delete normalized.turnId;
|
|
47
|
+
if (normalizedDeliveryId) normalized.deliveryId = normalizedDeliveryId;
|
|
48
|
+
else delete normalized.deliveryId;
|
|
49
|
+
if (normalizedConversationKey) normalized.conversationKey = normalizedConversationKey;
|
|
50
|
+
else delete normalized.conversationKey;
|
|
51
|
+
if (normalizedOpenerTurnId) normalized.openerTurnId = normalizedOpenerTurnId;
|
|
52
|
+
else delete normalized.openerTurnId;
|
|
53
|
+
if (normalizedOpenerDeliveryId) normalized.openerDeliveryId = normalizedOpenerDeliveryId;
|
|
54
|
+
else delete normalized.openerDeliveryId;
|
|
55
|
+
if (normalizedFailedAt) normalized.failedAt = normalizedFailedAt;
|
|
56
|
+
else delete normalized.failedAt;
|
|
57
|
+
|
|
58
|
+
const hasEstablishedEvidence = Boolean(
|
|
59
|
+
normalized.openerDeliveredAt
|
|
60
|
+
|| normalized.liveChatEstablishedAt,
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
if (hasEstablishedEvidence && (!normalized.status || ['queued', 'sent'].includes(normalized.status))) {
|
|
64
|
+
normalized.status = 'established';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (normalized.status === 'established') {
|
|
68
|
+
const establishedAt = normalizeAcceptedChatKickoffField(
|
|
69
|
+
normalized.liveChatEstablishedAt,
|
|
70
|
+
normalizeAcceptedChatKickoffField(
|
|
71
|
+
normalized.openerDeliveredAt,
|
|
72
|
+
normalizeAcceptedChatKickoffField(normalized.openerAcceptedAt, null),
|
|
73
|
+
),
|
|
74
|
+
);
|
|
75
|
+
if (!normalized.openerDeliveredAt && normalized.openerAcceptedAt) {
|
|
76
|
+
normalized.openerDeliveredAt = normalized.openerAcceptedAt;
|
|
77
|
+
}
|
|
78
|
+
if (!normalized.liveChatEstablishedAt && establishedAt) {
|
|
79
|
+
normalized.liveChatEstablishedAt = establishedAt;
|
|
80
|
+
}
|
|
81
|
+
if (String(normalized.reason || '').startsWith('queued_')) {
|
|
82
|
+
delete normalized.reason;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return normalized;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export async function markAcceptedChatKickoffFailureWithDeps(deps, {
|
|
90
|
+
requestId = null,
|
|
91
|
+
reason = 'accepted_chat_kickoff_failed',
|
|
92
|
+
turnId = null,
|
|
93
|
+
conversationKey = null,
|
|
94
|
+
} = {}) {
|
|
95
|
+
const { store, pushToAgent } = deps;
|
|
96
|
+
const normalizedRequestId = normalizeOptionalText(requestId);
|
|
97
|
+
if (!normalizedRequestId) return null;
|
|
98
|
+
const request = store.getChatRequest(normalizedRequestId);
|
|
99
|
+
if (!request) return null;
|
|
100
|
+
|
|
101
|
+
request.kickoff = normalizeAcceptedChatKickoffRecord({
|
|
102
|
+
...(request.kickoff && typeof request.kickoff === 'object' && !Array.isArray(request.kickoff) ? request.kickoff : {}),
|
|
103
|
+
status: 'failed',
|
|
104
|
+
reason: normalizeOptionalText(reason) || 'accepted_chat_kickoff_failed',
|
|
105
|
+
...(normalizeOptionalText(turnId) ? { turnId: normalizeOptionalText(turnId) } : {}),
|
|
106
|
+
...(normalizeOptionalText(conversationKey) ? { conversationKey: normalizeOptionalText(conversationKey) } : {}),
|
|
107
|
+
failedAt: store.now(),
|
|
108
|
+
});
|
|
109
|
+
if (store.markChatRequestUpdated) {
|
|
110
|
+
await store.markChatRequestUpdated();
|
|
111
|
+
}
|
|
112
|
+
await pushToAgent(request.fromAgentId, 'request.updated', request);
|
|
113
|
+
await pushToAgent(request.toAgentId, 'request.updated', request);
|
|
114
|
+
return request;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export async function markAcceptedChatKickoffProgressWithDeps(deps, {
|
|
118
|
+
requestId = null,
|
|
119
|
+
status = null,
|
|
120
|
+
reason = null,
|
|
121
|
+
turnId = null,
|
|
122
|
+
deliveryId = null,
|
|
123
|
+
conversationKey = null,
|
|
124
|
+
senderKickoffDeliveredAt = null,
|
|
125
|
+
openerAcceptedAt = null,
|
|
126
|
+
openerDeliveredAt = null,
|
|
127
|
+
liveChatEstablishedAt = null,
|
|
128
|
+
openerTurnId = null,
|
|
129
|
+
openerDeliveryId = null,
|
|
130
|
+
} = {}) {
|
|
131
|
+
const { store, pushToAgent } = deps;
|
|
132
|
+
const normalizedRequestId = normalizeOptionalText(requestId);
|
|
133
|
+
if (!normalizedRequestId) return null;
|
|
134
|
+
const request = store.getChatRequest(normalizedRequestId);
|
|
135
|
+
if (!request) return null;
|
|
136
|
+
|
|
137
|
+
request.kickoff = normalizeAcceptedChatKickoffRecord({
|
|
138
|
+
...(request.kickoff && typeof request.kickoff === 'object' && !Array.isArray(request.kickoff) ? request.kickoff : {}),
|
|
139
|
+
...(normalizeOptionalText(status) ? { status: normalizeOptionalText(status) } : {}),
|
|
140
|
+
...(normalizeOptionalText(reason) ? { reason: normalizeOptionalText(reason) } : {}),
|
|
141
|
+
...(normalizeOptionalText(turnId) ? { turnId: normalizeOptionalText(turnId) } : {}),
|
|
142
|
+
...(normalizeOptionalText(deliveryId) ? { deliveryId: normalizeOptionalText(deliveryId) } : {}),
|
|
143
|
+
...(normalizeOptionalText(conversationKey) ? { conversationKey: normalizeOptionalText(conversationKey) } : {}),
|
|
144
|
+
...(normalizeOptionalText(senderKickoffDeliveredAt)
|
|
145
|
+
? {
|
|
146
|
+
senderKickoffDeliveredAt: normalizeOptionalText(senderKickoffDeliveredAt),
|
|
147
|
+
deliveredAt: normalizeOptionalText(senderKickoffDeliveredAt),
|
|
148
|
+
}
|
|
149
|
+
: {}),
|
|
150
|
+
...(normalizeOptionalText(openerAcceptedAt) ? { openerAcceptedAt: normalizeOptionalText(openerAcceptedAt) } : {}),
|
|
151
|
+
...(normalizeOptionalText(openerDeliveredAt) ? { openerDeliveredAt: normalizeOptionalText(openerDeliveredAt) } : {}),
|
|
152
|
+
...(normalizeOptionalText(liveChatEstablishedAt) ? { liveChatEstablishedAt: normalizeOptionalText(liveChatEstablishedAt) } : {}),
|
|
153
|
+
...(normalizeOptionalText(openerTurnId) ? { openerTurnId: normalizeOptionalText(openerTurnId) } : {}),
|
|
154
|
+
...(normalizeOptionalText(openerDeliveryId) ? { openerDeliveryId: normalizeOptionalText(openerDeliveryId) } : {}),
|
|
155
|
+
});
|
|
156
|
+
if (store.markChatRequestUpdated) {
|
|
157
|
+
await store.markChatRequestUpdated();
|
|
158
|
+
}
|
|
159
|
+
await pushToAgent(request.fromAgentId, 'request.updated', request);
|
|
160
|
+
await pushToAgent(request.toAgentId, 'request.updated', request);
|
|
161
|
+
return request;
|
|
162
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export function normalizePositiveInteger(value, fallback) {
|
|
2
|
+
const normalized = Number(value);
|
|
3
|
+
if (!Number.isFinite(normalized) || normalized <= 0) return fallback;
|
|
4
|
+
return Math.floor(normalized);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function normalizeOptionalText(value) {
|
|
8
|
+
if (typeof value !== 'string') return null;
|
|
9
|
+
const normalized = value.trim();
|
|
10
|
+
return normalized || null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function cloneJsonObject(value) {
|
|
14
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
|
|
15
|
+
try {
|
|
16
|
+
const cloned = JSON.parse(JSON.stringify(value));
|
|
17
|
+
if (!cloned || typeof cloned !== 'object' || Array.isArray(cloned)) return null;
|
|
18
|
+
return cloned;
|
|
19
|
+
} catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function buildFailureBody(reason, extras = {}) {
|
|
25
|
+
return {
|
|
26
|
+
error: reason,
|
|
27
|
+
reason,
|
|
28
|
+
...extras,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import claworldPackageJson from '../../../package.json' with { type: 'json' };
|
|
2
3
|
|
|
3
4
|
import {
|
|
4
5
|
applyRuntimeIdentity,
|
|
@@ -57,6 +58,8 @@ import {
|
|
|
57
58
|
} from '../../lib/runtime-errors.js';
|
|
58
59
|
import { PUBLIC_IDENTITY_STATUS } from '../../lib/public-identity.js';
|
|
59
60
|
|
|
61
|
+
const CLAWORLD_PLUGIN_VERSION = claworldPackageJson.version;
|
|
62
|
+
|
|
60
63
|
function normalizeRelayHttpBaseUrl(serverUrl) {
|
|
61
64
|
const parsed = new URL(serverUrl);
|
|
62
65
|
if (parsed.protocol === 'ws:') parsed.protocol = 'http:';
|
|
@@ -174,6 +177,20 @@ const CLAWORLD_RELAY_OPERATIONAL_NOTICE_PATTERNS = [
|
|
|
174
177
|
/^⚠️\s*Agent failed before reply:/i,
|
|
175
178
|
];
|
|
176
179
|
|
|
180
|
+
// Older/runtime-variant OpenClaw hosts may surface provider/runtime failures as
|
|
181
|
+
// plain final text without setting `isError`. Keep this fallback at the bridge
|
|
182
|
+
// boundary so business logic never has to guess.
|
|
183
|
+
const CLAWORLD_RELAY_RUNTIME_ERROR_PATTERNS = [
|
|
184
|
+
/^⚠️\s*Agent failed before reply:/i,
|
|
185
|
+
/^LLM request failed:/i,
|
|
186
|
+
/^LLM request timed out\./i,
|
|
187
|
+
/^LLM request unauthorized\./i,
|
|
188
|
+
/^The AI service is temporarily overloaded\./i,
|
|
189
|
+
/^The AI service returned an error\./i,
|
|
190
|
+
/^⚠️\s*API rate limit reached\./i,
|
|
191
|
+
/^⚠️\s*.+\s+returned a billing error\b/i,
|
|
192
|
+
];
|
|
193
|
+
|
|
177
194
|
const CLAWORLD_RELAY_OPERATIONAL_SUFFIX_PATTERNS = [
|
|
178
195
|
/^Usage:\s+.+\s+in\s+\/\s+.+\s+out(?:\s+·\s+est\s+.+)?$/i,
|
|
179
196
|
];
|
|
@@ -201,18 +218,21 @@ function classifyRelayContinuationText(text) {
|
|
|
201
218
|
if (!normalized) {
|
|
202
219
|
return {
|
|
203
220
|
text: '',
|
|
204
|
-
|
|
221
|
+
operationalNotice: Boolean(String(text || '').trim()),
|
|
222
|
+
runtimeError: false,
|
|
205
223
|
};
|
|
206
224
|
}
|
|
207
225
|
if (CLAWORLD_RELAY_OPERATIONAL_NOTICE_PATTERNS.some((pattern) => pattern.test(normalized))) {
|
|
208
226
|
return {
|
|
209
227
|
text: '',
|
|
210
|
-
|
|
228
|
+
operationalNotice: true,
|
|
229
|
+
runtimeError: false,
|
|
211
230
|
};
|
|
212
231
|
}
|
|
213
232
|
return {
|
|
214
233
|
text: normalized,
|
|
215
|
-
|
|
234
|
+
operationalNotice: false,
|
|
235
|
+
runtimeError: false,
|
|
216
236
|
};
|
|
217
237
|
}
|
|
218
238
|
|
|
@@ -220,6 +240,45 @@ function sanitizeRelayContinuationText(text) {
|
|
|
220
240
|
return classifyRelayContinuationText(text).text;
|
|
221
241
|
}
|
|
222
242
|
|
|
243
|
+
function classifyRelayContinuationPayload(payload = {}) {
|
|
244
|
+
const rawText = String(payload?.text ?? payload?.body ?? '').trim();
|
|
245
|
+
const normalized = stripRelayOperationalSuffix(rawText);
|
|
246
|
+
const textClassification = classifyRelayContinuationText(rawText);
|
|
247
|
+
const runtimeError = payload?.isError === true
|
|
248
|
+
|| CLAWORLD_RELAY_RUNTIME_ERROR_PATTERNS.some((pattern) => pattern.test(normalized));
|
|
249
|
+
if (runtimeError) {
|
|
250
|
+
return {
|
|
251
|
+
text: '',
|
|
252
|
+
previewText: normalized,
|
|
253
|
+
operationalNotice: false,
|
|
254
|
+
runtimeError: true,
|
|
255
|
+
nonRenderable: true,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
return {
|
|
259
|
+
text: textClassification.text,
|
|
260
|
+
previewText: normalized,
|
|
261
|
+
operationalNotice: textClassification.operationalNotice,
|
|
262
|
+
runtimeError: false,
|
|
263
|
+
nonRenderable: textClassification.operationalNotice,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function resolveRelaySilentReason(runtimeOutputSummary = {}, continuation = {}) {
|
|
268
|
+
const counts = runtimeOutputSummary?.counts || {};
|
|
269
|
+
if (Number(counts.runtimeErrorFinal || 0) > 0) {
|
|
270
|
+
return 'runtime_failed_before_reply';
|
|
271
|
+
}
|
|
272
|
+
if (Number(counts.operationalNotice || 0) > 0 && Number(counts.nonRenderableFinal || 0) === Number(counts.final || 0)) {
|
|
273
|
+
return 'operational_notice_only';
|
|
274
|
+
}
|
|
275
|
+
const normalizedSource = normalizePluginOptionalText(continuation?.source);
|
|
276
|
+
if (normalizedSource && normalizedSource !== 'none') {
|
|
277
|
+
return normalizedSource;
|
|
278
|
+
}
|
|
279
|
+
return 'no_renderable_reply';
|
|
280
|
+
}
|
|
281
|
+
|
|
223
282
|
function previewRuntimeOutputText(text, maxLength = 120) {
|
|
224
283
|
const normalized = String(text || '').replace(/\s+/g, ' ').trim();
|
|
225
284
|
if (!normalized) return '';
|
|
@@ -1269,7 +1328,9 @@ function createDeliveryReplyDispatcher({
|
|
|
1269
1328
|
reasoningEnd: 0,
|
|
1270
1329
|
compactionStart: 0,
|
|
1271
1330
|
compactionEnd: 0,
|
|
1331
|
+
nonRenderableFinal: 0,
|
|
1272
1332
|
operationalNotice: 0,
|
|
1333
|
+
runtimeErrorFinal: 0,
|
|
1273
1334
|
},
|
|
1274
1335
|
previews: {
|
|
1275
1336
|
final: [],
|
|
@@ -1278,6 +1339,7 @@ function createDeliveryReplyDispatcher({
|
|
|
1278
1339
|
partial: [],
|
|
1279
1340
|
reasoning: [],
|
|
1280
1341
|
operationalNotice: [],
|
|
1342
|
+
runtimeErrorFinal: [],
|
|
1281
1343
|
},
|
|
1282
1344
|
relayContinuationSource: 'none',
|
|
1283
1345
|
relayContinuationPreview: null,
|
|
@@ -1288,14 +1350,21 @@ function createDeliveryReplyDispatcher({
|
|
|
1288
1350
|
runtimeOutputSummary.counts[kind] += 1;
|
|
1289
1351
|
const text = String(payload?.text ?? payload?.body ?? '').trim();
|
|
1290
1352
|
if (kind === 'final') {
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1353
|
+
const classified = classifyRelayContinuationPayload(payload);
|
|
1354
|
+
if (classified.text) {
|
|
1355
|
+
finalTexts.push(classified.text);
|
|
1356
|
+
appendRuntimeOutputPreview(runtimeOutputSummary.previews.final, classified.text);
|
|
1357
|
+
}
|
|
1358
|
+
if (classified.nonRenderable) {
|
|
1359
|
+
runtimeOutputSummary.counts.nonRenderableFinal += 1;
|
|
1360
|
+
}
|
|
1361
|
+
if (classified.operationalNotice) {
|
|
1362
|
+
runtimeOutputSummary.counts.operationalNotice += 1;
|
|
1363
|
+
appendRuntimeOutputPreview(runtimeOutputSummary.previews.operationalNotice, classified.previewText || text);
|
|
1364
|
+
}
|
|
1365
|
+
if (classified.runtimeError) {
|
|
1366
|
+
runtimeOutputSummary.counts.runtimeErrorFinal += 1;
|
|
1367
|
+
appendRuntimeOutputPreview(runtimeOutputSummary.previews.runtimeErrorFinal, classified.previewText || text);
|
|
1299
1368
|
}
|
|
1300
1369
|
return;
|
|
1301
1370
|
}
|
|
@@ -1411,21 +1480,35 @@ function createDeliveryReplyDispatcher({
|
|
|
1411
1480
|
const markDispatchIdle = async () => {
|
|
1412
1481
|
await dispatchApi.dispatcher.waitForIdle?.();
|
|
1413
1482
|
if (!replied && !suppressed) {
|
|
1414
|
-
const
|
|
1483
|
+
const allowPartialFallback = (
|
|
1484
|
+
runtimeOutputSummary.counts.final > 0
|
|
1485
|
+
&& finalTexts.length === 0
|
|
1486
|
+
&& blockTexts.length === 0
|
|
1487
|
+
&& runtimeOutputSummary.counts.nonRenderableFinal === 0
|
|
1488
|
+
);
|
|
1489
|
+
const safeContinuation = buildRelayContinuationText({
|
|
1415
1490
|
finalTexts,
|
|
1416
1491
|
blockTexts,
|
|
1417
1492
|
partialText: partialContinuationText,
|
|
1418
|
-
allowPartialFallback
|
|
1419
|
-
runtimeOutputSummary.counts.final > 0 && finalTexts.length === 0 && blockTexts.length === 0,
|
|
1493
|
+
allowPartialFallback,
|
|
1420
1494
|
});
|
|
1421
|
-
runtimeOutputSummary.relayContinuationSource =
|
|
1422
|
-
runtimeOutputSummary.relayContinuationPreview =
|
|
1423
|
-
? previewRuntimeOutputText(
|
|
1495
|
+
runtimeOutputSummary.relayContinuationSource = safeContinuation.source;
|
|
1496
|
+
runtimeOutputSummary.relayContinuationPreview = safeContinuation.text
|
|
1497
|
+
? previewRuntimeOutputText(safeContinuation.text)
|
|
1424
1498
|
: null;
|
|
1425
|
-
if (
|
|
1426
|
-
await flushReply(
|
|
1499
|
+
if (safeContinuation.text) {
|
|
1500
|
+
await flushReply(safeContinuation.text);
|
|
1427
1501
|
} else {
|
|
1428
|
-
|
|
1502
|
+
const silentReason = resolveRelaySilentReason(runtimeOutputSummary, safeContinuation);
|
|
1503
|
+
if (runtimeOutputSummary.counts.runtimeErrorFinal > 0) {
|
|
1504
|
+
logger.warn?.(`[claworld:${runtimeAccountId}] runtime produced non-renderable error finals; returning kept_silent`, {
|
|
1505
|
+
deliveryId,
|
|
1506
|
+
sessionKey,
|
|
1507
|
+
localAgentId,
|
|
1508
|
+
runtimeOutputSummary,
|
|
1509
|
+
});
|
|
1510
|
+
}
|
|
1511
|
+
await flushKeptSilent(silentReason);
|
|
1429
1512
|
}
|
|
1430
1513
|
}
|
|
1431
1514
|
await dispatchApi.markDispatchIdle?.();
|
|
@@ -1470,13 +1553,14 @@ function createDeliveryReplyDispatcher({
|
|
|
1470
1553
|
final: [...runtimeOutputSummary.previews.final],
|
|
1471
1554
|
block: [...runtimeOutputSummary.previews.block],
|
|
1472
1555
|
tool: [...runtimeOutputSummary.previews.tool],
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1556
|
+
partial: [...runtimeOutputSummary.previews.partial],
|
|
1557
|
+
reasoning: [...runtimeOutputSummary.previews.reasoning],
|
|
1558
|
+
operationalNotice: [...runtimeOutputSummary.previews.operationalNotice],
|
|
1559
|
+
runtimeErrorFinal: [...runtimeOutputSummary.previews.runtimeErrorFinal],
|
|
1560
|
+
},
|
|
1561
|
+
relayContinuationSource: runtimeOutputSummary.relayContinuationSource,
|
|
1562
|
+
relayContinuationPreview: runtimeOutputSummary.relayContinuationPreview,
|
|
1563
|
+
replyTransport,
|
|
1480
1564
|
replyFallbackUsed,
|
|
1481
1565
|
keptSilentTransport,
|
|
1482
1566
|
keptSilentFallbackUsed,
|
|
@@ -1749,8 +1833,8 @@ async function maybeBridgeRuntimeDelivery({
|
|
|
1749
1833
|
&& metadata.allowReply !== false
|
|
1750
1834
|
&& replied !== true
|
|
1751
1835
|
&& runtimeOutputSummary.counts.final > 0
|
|
1752
|
-
&& runtimeOutputSummary.counts.
|
|
1753
|
-
&& runtimeOutputSummary.counts.final === runtimeOutputSummary.counts.
|
|
1836
|
+
&& runtimeOutputSummary.counts.nonRenderableFinal > 0
|
|
1837
|
+
&& runtimeOutputSummary.counts.final === runtimeOutputSummary.counts.nonRenderableFinal
|
|
1754
1838
|
&& runtimeOutputSummary.counts.block === 0
|
|
1755
1839
|
&& runtimeOutputSummary.counts.tool === 0
|
|
1756
1840
|
&& runtimeOutputSummary.counts.partial === 0
|
|
@@ -2369,7 +2453,7 @@ export function createClaworldChannelPlugin({
|
|
|
2369
2453
|
return {
|
|
2370
2454
|
ok: true,
|
|
2371
2455
|
pluginId: 'claworld',
|
|
2372
|
-
version:
|
|
2456
|
+
version: CLAWORLD_PLUGIN_VERSION,
|
|
2373
2457
|
defaultAccountId: null,
|
|
2374
2458
|
accounts: accountSnapshots,
|
|
2375
2459
|
relayClients: Object.fromEntries(
|
|
@@ -2518,7 +2602,7 @@ async function generateRuntimeProfileCard(context = {}) {
|
|
|
2518
2602
|
docsPath: '/channels/claworld',
|
|
2519
2603
|
docsLabel: 'claworld',
|
|
2520
2604
|
blurb: 'Claworld relay channel backed by the Claworld backend.',
|
|
2521
|
-
version:
|
|
2605
|
+
version: CLAWORLD_PLUGIN_VERSION,
|
|
2522
2606
|
forceAccountBinding: true,
|
|
2523
2607
|
},
|
|
2524
2608
|
onboarding: claworldOnboardingAdapter,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { normalizeAcceptedChatKickoffRecord } from '../../lib/relay/kickoff-progress.js';
|
|
2
|
+
|
|
1
3
|
function normalizeText(value, fallback = null) {
|
|
2
4
|
if (value == null) return fallback;
|
|
3
5
|
const normalized = String(value).trim();
|
|
@@ -437,15 +439,19 @@ function normalizeConversationScopeDetails(input = {}) {
|
|
|
437
439
|
}
|
|
438
440
|
|
|
439
441
|
function projectChatRequestKickoff(kickoff = {}) {
|
|
440
|
-
|
|
442
|
+
const normalizedKickoff = normalizeAcceptedChatKickoffRecord(kickoff, { fallbackStatus: 'skipped' });
|
|
443
|
+
if (!normalizedKickoff) return null;
|
|
441
444
|
return {
|
|
442
|
-
status: normalizeText(
|
|
443
|
-
deliveredAt: normalizeText(
|
|
444
|
-
senderKickoffDeliveredAt: normalizeText(
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
445
|
+
status: normalizeText(normalizedKickoff.status, 'skipped'),
|
|
446
|
+
deliveredAt: normalizeText(normalizedKickoff.deliveredAt, null),
|
|
447
|
+
senderKickoffDeliveredAt: normalizeText(
|
|
448
|
+
normalizedKickoff.senderKickoffDeliveredAt,
|
|
449
|
+
normalizeText(normalizedKickoff.deliveredAt, null),
|
|
450
|
+
),
|
|
451
|
+
openerAcceptedAt: normalizeText(normalizedKickoff.openerAcceptedAt, null),
|
|
452
|
+
openerDeliveredAt: normalizeText(normalizedKickoff.openerDeliveredAt, null),
|
|
453
|
+
liveChatEstablishedAt: normalizeText(normalizedKickoff.liveChatEstablishedAt, null),
|
|
454
|
+
reason: normalizeText(normalizedKickoff.reason, null),
|
|
449
455
|
};
|
|
450
456
|
}
|
|
451
457
|
|