@coolclaw/coolclaw 1.0.6 → 1.0.7
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.
|
@@ -154,13 +154,24 @@ function validateAgentAction(action, task) {
|
|
|
154
154
|
if (!option) {
|
|
155
155
|
return { ok: false, reason: "disallowed_action_type" };
|
|
156
156
|
}
|
|
157
|
-
if (
|
|
157
|
+
if (containsPublicPrivateInfoLeak(action.actionType, action.actionData)) {
|
|
158
|
+
return { ok: false, reason: "public_private_info_leak" };
|
|
159
|
+
}
|
|
160
|
+
const repaired = repairActionDataForSchema(action.actionData, option.actionDataSchema);
|
|
161
|
+
if (!matchesActionDataSchema(repaired.actionData, option.actionDataSchema)) {
|
|
158
162
|
return { ok: false, reason: "invalid_action_shape" };
|
|
159
163
|
}
|
|
160
|
-
if (containsPublicPrivateInfoLeak(action.actionType,
|
|
164
|
+
if (containsPublicPrivateInfoLeak(action.actionType, repaired.actionData)) {
|
|
161
165
|
return { ok: false, reason: "public_private_info_leak" };
|
|
162
166
|
}
|
|
163
|
-
return {
|
|
167
|
+
return {
|
|
168
|
+
ok: true,
|
|
169
|
+
action: {
|
|
170
|
+
actionType: action.actionType,
|
|
171
|
+
actionData: repaired.actionData
|
|
172
|
+
},
|
|
173
|
+
repairReason: repaired.repairReason
|
|
174
|
+
};
|
|
164
175
|
}
|
|
165
176
|
function backendFallbackAction(task) {
|
|
166
177
|
const fallback = task.fallbackAction;
|
|
@@ -218,6 +229,39 @@ function matchesActionDataSchema(actionData, schema) {
|
|
|
218
229
|
}
|
|
219
230
|
return true;
|
|
220
231
|
}
|
|
232
|
+
function repairActionDataForSchema(actionData, schema) {
|
|
233
|
+
if (!schema || Object.keys(schema).length === 0) {
|
|
234
|
+
return { actionData };
|
|
235
|
+
}
|
|
236
|
+
const properties = isRecord(schema.properties) ? schema.properties : {};
|
|
237
|
+
let repaired = null;
|
|
238
|
+
const truncatedFields = [];
|
|
239
|
+
for (const [field, propertySchema] of Object.entries(properties)) {
|
|
240
|
+
const value = actionData[field];
|
|
241
|
+
if (typeof value !== "string" || !isRecord(propertySchema)) {
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
if (propertySchema.type !== "string" || typeof propertySchema.maxLength !== "number") {
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
const maxLength = Math.max(0, Math.floor(propertySchema.maxLength));
|
|
248
|
+
if (value.length <= maxLength) {
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (!repaired) {
|
|
252
|
+
repaired = { ...actionData };
|
|
253
|
+
}
|
|
254
|
+
repaired[field] = value.slice(0, maxLength);
|
|
255
|
+
truncatedFields.push(field);
|
|
256
|
+
}
|
|
257
|
+
if (truncatedFields.length === 0) {
|
|
258
|
+
return { actionData };
|
|
259
|
+
}
|
|
260
|
+
return {
|
|
261
|
+
actionData: repaired ?? actionData,
|
|
262
|
+
repairReason: `truncate:${truncatedFields.join(",")}`
|
|
263
|
+
};
|
|
264
|
+
}
|
|
221
265
|
function matchesSchemaValue(value, schema, required) {
|
|
222
266
|
if (value == null) return !required;
|
|
223
267
|
if (!isRecord(schema)) return true;
|
|
@@ -723,6 +767,7 @@ async function sendGameAction(input) {
|
|
|
723
767
|
timestamp: String(Date.now()),
|
|
724
768
|
turnSeq: input.turnSeq,
|
|
725
769
|
eventId: input.eventId,
|
|
770
|
+
deadlineEpochMs: input.deadlineEpochMs,
|
|
726
771
|
traceId: input.traceId,
|
|
727
772
|
promptPolicyVersion: input.promptPolicyVersion,
|
|
728
773
|
renderedPromptHash: input.renderedPromptHash,
|
|
@@ -737,6 +782,7 @@ async function sendGameAction(input) {
|
|
|
737
782
|
if (response.ok === false) {
|
|
738
783
|
throw new Error(response.error?.message ?? "CoolClaw game action failed");
|
|
739
784
|
}
|
|
785
|
+
return response;
|
|
740
786
|
}
|
|
741
787
|
|
|
742
788
|
// src/game-action-parser.ts
|
|
@@ -811,7 +857,16 @@ function parseActionJson(body) {
|
|
|
811
857
|
try {
|
|
812
858
|
obj = JSON.parse(body);
|
|
813
859
|
} catch (e) {
|
|
814
|
-
|
|
860
|
+
const repaired = removeTrailingCommas(body);
|
|
861
|
+
if (repaired !== body) {
|
|
862
|
+
try {
|
|
863
|
+
obj = JSON.parse(repaired);
|
|
864
|
+
} catch {
|
|
865
|
+
return { error: "invalid_json", detail: e instanceof Error ? e.message : String(e) };
|
|
866
|
+
}
|
|
867
|
+
} else {
|
|
868
|
+
return { error: "invalid_json", detail: e instanceof Error ? e.message : String(e) };
|
|
869
|
+
}
|
|
815
870
|
}
|
|
816
871
|
if (typeof obj !== "object" || obj === null) {
|
|
817
872
|
return { error: "invalid_json", detail: "not an object" };
|
|
@@ -828,6 +883,41 @@ function parseActionJson(body) {
|
|
|
828
883
|
actionData: rec.actionData
|
|
829
884
|
};
|
|
830
885
|
}
|
|
886
|
+
function removeTrailingCommas(body) {
|
|
887
|
+
let out = "";
|
|
888
|
+
let inString = false;
|
|
889
|
+
let escaped = false;
|
|
890
|
+
for (let i = 0; i < body.length; i += 1) {
|
|
891
|
+
const ch = body[i];
|
|
892
|
+
if (inString) {
|
|
893
|
+
out += ch;
|
|
894
|
+
if (escaped) {
|
|
895
|
+
escaped = false;
|
|
896
|
+
} else if (ch === "\\") {
|
|
897
|
+
escaped = true;
|
|
898
|
+
} else if (ch === '"') {
|
|
899
|
+
inString = false;
|
|
900
|
+
}
|
|
901
|
+
continue;
|
|
902
|
+
}
|
|
903
|
+
if (ch === '"') {
|
|
904
|
+
inString = true;
|
|
905
|
+
out += ch;
|
|
906
|
+
continue;
|
|
907
|
+
}
|
|
908
|
+
if (ch === ",") {
|
|
909
|
+
let j = i + 1;
|
|
910
|
+
while (j < body.length && /\s/.test(body[j])) {
|
|
911
|
+
j += 1;
|
|
912
|
+
}
|
|
913
|
+
if (body[j] === "}" || body[j] === "]") {
|
|
914
|
+
continue;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
out += ch;
|
|
918
|
+
}
|
|
919
|
+
return out;
|
|
920
|
+
}
|
|
831
921
|
|
|
832
922
|
// src/game-action-audit.ts
|
|
833
923
|
function normalizeAuditText(value, maxChars = 256) {
|
|
@@ -1149,7 +1239,7 @@ function logAckFailure(params) {
|
|
|
1149
1239
|
async function submitGameActionWithLog(action, meta, wsClient, log, source, rawResponse, auditMeta) {
|
|
1150
1240
|
if (!wsClient.isConnected()) {
|
|
1151
1241
|
log?.error?.(`[GAME-ACTION] submit skipped: ws not connected eventId=${meta.eventId}`);
|
|
1152
|
-
return
|
|
1242
|
+
return "failed";
|
|
1153
1243
|
}
|
|
1154
1244
|
const responseHash = rawResponse && rawResponse.length > 0 ? sha256Hex(rawResponse) : void 0;
|
|
1155
1245
|
log?.info?.(
|
|
@@ -1157,7 +1247,7 @@ async function submitGameActionWithLog(action, meta, wsClient, log, source, rawR
|
|
|
1157
1247
|
);
|
|
1158
1248
|
const start = Date.now();
|
|
1159
1249
|
try {
|
|
1160
|
-
await sendGameAction({
|
|
1250
|
+
const response = await sendGameAction({
|
|
1161
1251
|
client: wsClient,
|
|
1162
1252
|
gameId: meta.gameId,
|
|
1163
1253
|
roomId: meta.roomId,
|
|
@@ -1166,6 +1256,7 @@ async function submitGameActionWithLog(action, meta, wsClient, log, source, rawR
|
|
|
1166
1256
|
actionData: action.actionData,
|
|
1167
1257
|
turnSeq: meta.turnSeq,
|
|
1168
1258
|
eventId: meta.eventId,
|
|
1259
|
+
deadlineEpochMs: meta.deadlineEpochMs,
|
|
1169
1260
|
traceId: meta.traceId,
|
|
1170
1261
|
promptPolicyVersion: meta.promptPolicyVersion,
|
|
1171
1262
|
renderedPromptHash: meta.renderedPromptHash,
|
|
@@ -1176,16 +1267,28 @@ async function submitGameActionWithLog(action, meta, wsClient, log, source, rawR
|
|
|
1176
1267
|
modelActionType: auditMeta?.modelActionType,
|
|
1177
1268
|
validationReason: normalizeAuditText(auditMeta?.validationReason)
|
|
1178
1269
|
});
|
|
1270
|
+
if (response.uncertain === true) {
|
|
1271
|
+
log?.warn?.(
|
|
1272
|
+
`[GAME-ACTION] submit uncertain source=${source} eventId=${meta.eventId} elapsedMs=${Date.now() - start} msg=${response.message ?? ""}`
|
|
1273
|
+
);
|
|
1274
|
+
return "uncertain";
|
|
1275
|
+
}
|
|
1179
1276
|
log?.info?.(
|
|
1180
1277
|
`[GAME-ACTION] submit ok source=${source} gameId=${meta.gameId} eventId=${meta.eventId} promptPolicyVersion=${meta.promptPolicyVersion ?? ""} renderedPromptHash=${meta.renderedPromptHash ?? ""} rawResponseHash=${responseHash ?? ""} elapsedMs=${Date.now() - start}`
|
|
1181
1278
|
);
|
|
1182
|
-
return
|
|
1279
|
+
return "submitted";
|
|
1183
1280
|
} catch (err) {
|
|
1184
1281
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
1282
|
+
if (isGameActionSubmitUncertainError(errMsg)) {
|
|
1283
|
+
log?.warn?.(
|
|
1284
|
+
`[GAME-ACTION] submit uncertain source=${source} eventId=${meta.eventId} elapsedMs=${Date.now() - start} err=${errMsg}`
|
|
1285
|
+
);
|
|
1286
|
+
return "uncertain";
|
|
1287
|
+
}
|
|
1185
1288
|
log?.error?.(
|
|
1186
1289
|
`[GAME-ACTION] submit failed source=${source} eventId=${meta.eventId} elapsedMs=${Date.now() - start} err=${errMsg}`
|
|
1187
1290
|
);
|
|
1188
|
-
return
|
|
1291
|
+
return "failed";
|
|
1189
1292
|
}
|
|
1190
1293
|
}
|
|
1191
1294
|
async function submitBackendFallbackWithLog(params) {
|
|
@@ -1194,7 +1297,7 @@ async function submitBackendFallbackWithLog(params) {
|
|
|
1194
1297
|
params.log?.warn?.(
|
|
1195
1298
|
`[GAME-ACTION] backend fallback unavailable eventType=${params.meta.eventType} eventId=${params.meta.eventId} reason=${params.reason} promptPolicyVersion=${params.meta.promptPolicyVersion ?? ""} renderedPromptHash=${params.meta.renderedPromptHash ?? ""}`
|
|
1196
1299
|
);
|
|
1197
|
-
return
|
|
1300
|
+
return "failed";
|
|
1198
1301
|
}
|
|
1199
1302
|
const inferred = inferRejectedModelAction(params.rawResponse ?? "", params.meta.agentTask);
|
|
1200
1303
|
const auditMeta = {
|
|
@@ -1215,6 +1318,9 @@ async function submitBackendFallbackWithLog(params) {
|
|
|
1215
1318
|
auditMeta
|
|
1216
1319
|
);
|
|
1217
1320
|
}
|
|
1321
|
+
function isGameActionSubmitUncertainError(message) {
|
|
1322
|
+
return /request timed out|wss client stopped|websocket.*clos|socket hang up|econnreset|write epipe/i.test(message);
|
|
1323
|
+
}
|
|
1218
1324
|
var runtimeClients = /* @__PURE__ */ new Map();
|
|
1219
1325
|
function setRuntimeClient(accountKey, client) {
|
|
1220
1326
|
runtimeClients.set(accountKey, client);
|
|
@@ -1386,7 +1492,7 @@ var coolclawChannelPlugin = createChatChannelPlugin({
|
|
|
1386
1492
|
log: ctx.log,
|
|
1387
1493
|
reason: "runtime_not_available"
|
|
1388
1494
|
});
|
|
1389
|
-
if (
|
|
1495
|
+
if (submitted === "failed") {
|
|
1390
1496
|
throw new Error("game fallback submit failed: runtime_not_available");
|
|
1391
1497
|
}
|
|
1392
1498
|
}
|
|
@@ -1509,10 +1615,11 @@ var coolclawChannelPlugin = createChatChannelPlugin({
|
|
|
1509
1615
|
full,
|
|
1510
1616
|
{
|
|
1511
1617
|
modelActionRejected: false,
|
|
1512
|
-
modelActionType: validation.action.actionType
|
|
1618
|
+
modelActionType: validation.action.actionType,
|
|
1619
|
+
validationReason: validation.repairReason
|
|
1513
1620
|
}
|
|
1514
1621
|
);
|
|
1515
|
-
if (submitted) {
|
|
1622
|
+
if (submitted === "submitted" || submitted === "uncertain") {
|
|
1516
1623
|
gameSubmitted = true;
|
|
1517
1624
|
} else {
|
|
1518
1625
|
gameFallbackReason = `llm_action_submit_failed:${validation.action.actionType}`;
|
|
@@ -1580,7 +1687,7 @@ var coolclawChannelPlugin = createChatChannelPlugin({
|
|
|
1580
1687
|
validationReason: gameFallbackReason ?? gameValidationReason ?? inferred.validationReason
|
|
1581
1688
|
}
|
|
1582
1689
|
});
|
|
1583
|
-
if (
|
|
1690
|
+
if (submitted === "failed") {
|
|
1584
1691
|
throw new Error(`game fallback submit failed: ${gameFallbackReason ?? "unknown"}`);
|
|
1585
1692
|
}
|
|
1586
1693
|
} catch (fbErr) {
|
package/dist/cli-metadata.js
CHANGED
package/dist/index.js
CHANGED
package/dist/setup-entry.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coolclaw/coolclaw",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "OpenClaw native channel plugin for Riddle/CoolClaw chat.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"runtimeSetupEntry": "./dist/setup-entry.js",
|
|
73
73
|
"install": {
|
|
74
74
|
"npmSpec": "@coolclaw/coolclaw",
|
|
75
|
-
"expectedIntegrity": "sha512-
|
|
75
|
+
"expectedIntegrity": "sha512-nLVphLOrmsFhxyJU8neAdx4bE+EcJjLnmzGZmt9E9ndUqiPAjbJCb8pOv7HXYfHeQeVFnf42HkmVrUeqro3ClQ==",
|
|
76
76
|
"defaultChoice": "npm",
|
|
77
77
|
"minHostVersion": ">=2026.3.22"
|
|
78
78
|
},
|