@coolclaw/coolclaw 1.0.18 → 1.0.20
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.
|
@@ -224,19 +224,21 @@ function validateAgentAction(action, task) {
|
|
|
224
224
|
if (!matchesActionDataSchema(repaired.actionData, option.actionDataSchema)) {
|
|
225
225
|
return { ok: false, reason: "invalid_action_shape" };
|
|
226
226
|
}
|
|
227
|
-
if (isStructuredJsonTask(task) && !matchesRootOutputSchema(action, task.outputSchema)) {
|
|
228
|
-
return { ok: false, reason: "invalid_action_shape" };
|
|
229
|
-
}
|
|
230
227
|
const normalizedAction = {
|
|
231
228
|
actionType: action.actionType,
|
|
232
229
|
actionData: repaired.actionData
|
|
233
230
|
};
|
|
234
231
|
if (typeof action.speech === "string") normalizedAction.speech = action.speech;
|
|
235
232
|
if (typeof action.voteReason === "string") normalizedAction.voteReason = action.voteReason;
|
|
233
|
+
const shouldValidateRoot = isStructuredJsonTask(task);
|
|
234
|
+
const repairedRoot = shouldValidateRoot ? repairRootOutputForSchema(normalizedAction, task.outputSchema) : { action: normalizedAction };
|
|
235
|
+
if (!repairedRoot || shouldValidateRoot && !matchesRootOutputSchema(repairedRoot.action, task.outputSchema)) {
|
|
236
|
+
return { ok: false, reason: "invalid_action_shape" };
|
|
237
|
+
}
|
|
236
238
|
return {
|
|
237
239
|
ok: true,
|
|
238
|
-
action:
|
|
239
|
-
repairReason: repaired.repairReason
|
|
240
|
+
action: repairedRoot.action,
|
|
241
|
+
repairReason: combineRepairReasons(repaired.repairReason, repairedRoot.repairReason)
|
|
240
242
|
};
|
|
241
243
|
}
|
|
242
244
|
function backendFallbackAction(task) {
|
|
@@ -330,7 +332,7 @@ function repairActionDataForSchema(actionData, schema) {
|
|
|
330
332
|
if (!repaired) {
|
|
331
333
|
repaired = { ...actionData };
|
|
332
334
|
}
|
|
333
|
-
repaired[field] = value
|
|
335
|
+
repaired[field] = truncateWithEllipsis(value, maxLength);
|
|
334
336
|
truncatedFields.push(field);
|
|
335
337
|
}
|
|
336
338
|
if (truncatedFields.length === 0) {
|
|
@@ -341,6 +343,54 @@ function repairActionDataForSchema(actionData, schema) {
|
|
|
341
343
|
repairReason: truncatedFields.map((field) => `${field}_too_long`).join(",")
|
|
342
344
|
};
|
|
343
345
|
}
|
|
346
|
+
function repairRootOutputForSchema(action, schema) {
|
|
347
|
+
if (!schema || Object.keys(schema).length === 0) {
|
|
348
|
+
return { action };
|
|
349
|
+
}
|
|
350
|
+
const properties = isRecord(schema.properties) ? schema.properties : {};
|
|
351
|
+
let repaired = null;
|
|
352
|
+
const truncatedFields = [];
|
|
353
|
+
for (const field of ["speech", "voteReason"]) {
|
|
354
|
+
const propertySchema = properties[field];
|
|
355
|
+
const value = action[field];
|
|
356
|
+
if (typeof value !== "string" || !isRecord(propertySchema)) {
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
if (!schemaAllowsType(propertySchema.type, "string") || typeof propertySchema.maxLength !== "number") {
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
const maxLength = Math.max(0, Math.floor(propertySchema.maxLength));
|
|
363
|
+
if (value.length <= maxLength) {
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
if (!repaired) {
|
|
367
|
+
repaired = { ...action };
|
|
368
|
+
}
|
|
369
|
+
repaired[field] = truncateWithEllipsis(value, maxLength);
|
|
370
|
+
truncatedFields.push(field);
|
|
371
|
+
}
|
|
372
|
+
if (truncatedFields.length === 0) {
|
|
373
|
+
return { action };
|
|
374
|
+
}
|
|
375
|
+
return {
|
|
376
|
+
action: repaired ?? action,
|
|
377
|
+
repairReason: truncatedFields.map((field) => `${field}_too_long`).join(",")
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
function combineRepairReasons(first, second) {
|
|
381
|
+
if (!first) return second;
|
|
382
|
+
if (!second) return first;
|
|
383
|
+
return `${first},${second}`;
|
|
384
|
+
}
|
|
385
|
+
function truncateWithEllipsis(value, maxLength) {
|
|
386
|
+
if (value.length <= maxLength) {
|
|
387
|
+
return value;
|
|
388
|
+
}
|
|
389
|
+
if (maxLength <= 3) {
|
|
390
|
+
return value.slice(0, Math.max(0, maxLength));
|
|
391
|
+
}
|
|
392
|
+
return `${value.slice(0, maxLength - 3)}...`;
|
|
393
|
+
}
|
|
344
394
|
function matchesSchemaValue(value, schema, required) {
|
|
345
395
|
if (!isRecord(schema)) return true;
|
|
346
396
|
if (value == null) {
|
|
@@ -1985,12 +2035,50 @@ function logAckFailure(params) {
|
|
|
1985
2035
|
const target = params.target ? ` target=${params.target}` : "";
|
|
1986
2036
|
params.log(`${params.channel} ack cleanup failed${target}: ${String(params.error)}`);
|
|
1987
2037
|
}
|
|
1988
|
-
function buildStructuredActionRetryPrompt(renderedPrompt, reason) {
|
|
2038
|
+
function buildStructuredActionRetryPrompt(renderedPrompt, reason, agentTask) {
|
|
1989
2039
|
const reasonText = reason && reason.trim().length > 0 ? reason.trim() : "invalid_output";
|
|
2040
|
+
const translatedReason = translateStructuredRetryReason(reasonText);
|
|
2041
|
+
const allowedActionTypes2 = agentTask?.actionContract?.options?.map((option) => option.actionType).filter((actionType) => typeof actionType === "string" && actionType.length > 0) ?? [];
|
|
2042
|
+
const allowedLine = allowedActionTypes2.length > 0 ? `
|
|
2043
|
+
\u5F53\u524D\u53EA\u5141\u8BB8 actionType\uFF1A${allowedActionTypes2.join("\u3001")}\u3002` : "";
|
|
2044
|
+
const forbiddenNames = [...forbiddenLegacyActionNames(allowedActionTypes2), "SUBMIT_ACTION", "reason", "content"];
|
|
2045
|
+
const forbiddenLine = allowedActionTypes2.length > 0 ? `
|
|
2046
|
+
\u4E0D\u8981\u4F7F\u7528 ${joinChineseOr(forbiddenNames)}\u3002` : "";
|
|
1990
2047
|
return `${renderedPrompt}
|
|
1991
2048
|
|
|
1992
|
-
|
|
1993
|
-
\u8BF7\u91CD\u65B0\
|
|
2049
|
+
${translatedReason}${allowedLine}${forbiddenLine}
|
|
2050
|
+
\u8BF7\u6309\u4E0A\u65B9\u3010\u8F93\u51FA\u683C\u5F0F\u3011\u91CD\u65B0\u8F93\u51FA\u5B8C\u6574 JSON\uFF1B\u53EA\u8F93\u51FA\u4E00\u4E2A\u5B8C\u6574 JSON \u5BF9\u8C61\uFF0C\u4E0D\u8981\u8F93\u51FA Markdown\u3001\u89E3\u91CA\u6587\u5B57\u6216\u4EE3\u7801\u5757\u3002`;
|
|
2051
|
+
}
|
|
2052
|
+
function translateStructuredRetryReason(reasonText) {
|
|
2053
|
+
if (reasonText === "disallowed_action_type") {
|
|
2054
|
+
return "\u4E0A\u4E00\u6B21\u8F93\u51FA\u672A\u88AB\u63A5\u53D7\uFF1AactionType \u4E0D\u5728\u5F53\u524D\u5141\u8BB8\u5217\u8868\u3002";
|
|
2055
|
+
}
|
|
2056
|
+
if (reasonText === "invalid_action_shape") {
|
|
2057
|
+
return "\u4E0A\u4E00\u6B21\u8F93\u51FA\u672A\u88AB\u63A5\u53D7\uFF1AJSON \u5B57\u6BB5\u7ED3\u6784\u4E0D\u7B26\u5408\u5F53\u524D\u3010\u8F93\u51FA\u683C\u5F0F\u3011\u3002";
|
|
2058
|
+
}
|
|
2059
|
+
if (reasonText === "missing_contract") {
|
|
2060
|
+
return "\u4E0A\u4E00\u6B21\u8F93\u51FA\u672A\u88AB\u63A5\u53D7\uFF1A\u5F53\u524D\u4EFB\u52A1\u7F3A\u5C11\u53EF\u63D0\u4EA4\u7684\u52A8\u4F5C\u5951\u7EA6\u3002";
|
|
2061
|
+
}
|
|
2062
|
+
return `\u4E0A\u4E00\u6B21\u8F93\u51FA\u672A\u88AB\u63A5\u53D7\uFF0C\u5931\u8D25\u539F\u56E0\uFF1A${reasonText}\u3002`;
|
|
2063
|
+
}
|
|
2064
|
+
function forbiddenLegacyActionNames(allowedActionTypes2) {
|
|
2065
|
+
const legacyNames = allowedActionTypes2.map((actionType) => {
|
|
2066
|
+
if (actionType === "WOLF_KILL") return "WOLF_TURN";
|
|
2067
|
+
if (actionType === "WITCH_SAVE" || actionType === "WITCH_POISON" || actionType === "WITCH_PASS") return "WITCH_TURN";
|
|
2068
|
+
if (actionType === "SEER_CHECK") return "SEER_TURN";
|
|
2069
|
+
if (actionType === "DAY_SPEAK") return "DAY_SPEAK_TURN";
|
|
2070
|
+
if (actionType === "DAY_VOTE") return "DAY_VOTE_TURN";
|
|
2071
|
+
if (actionType === "LAST_WORD") return "LAST_WORD_TURN";
|
|
2072
|
+
if (actionType === "HUNTER_SHOOT" || actionType === "HUNTER_PASS") return "HUNTER_SKILL_TURN";
|
|
2073
|
+
return void 0;
|
|
2074
|
+
}).filter((name) => Boolean(name));
|
|
2075
|
+
return [...new Set(legacyNames)];
|
|
2076
|
+
}
|
|
2077
|
+
function joinChineseOr(values) {
|
|
2078
|
+
if (values.length <= 1) {
|
|
2079
|
+
return values.join("");
|
|
2080
|
+
}
|
|
2081
|
+
return `${values.slice(0, -1).join("\u3001")} \u6216 ${values[values.length - 1]}`;
|
|
1994
2082
|
}
|
|
1995
2083
|
function hasStructuredRetryBudget(deadlineEpochMs, nowEpochMs = Date.now(), safetyMarginMs = 1e3) {
|
|
1996
2084
|
if (!deadlineEpochMs || deadlineEpochMs <= 0) {
|
|
@@ -2835,7 +2923,7 @@ var coolclawChannelPlugin = createChatChannelPlugin({
|
|
|
2835
2923
|
gameModelActionRejected = void 0;
|
|
2836
2924
|
gameModelActionType = void 0;
|
|
2837
2925
|
gameValidationReason = void 0;
|
|
2838
|
-
const retryPrompt = buildStructuredActionRetryPrompt(envelope.text, retryReason);
|
|
2926
|
+
const retryPrompt = buildStructuredActionRetryPrompt(envelope.text, retryReason, gameMeta.agentTask);
|
|
2839
2927
|
await dispatchGameReply({
|
|
2840
2928
|
...gameBaseReplyContext,
|
|
2841
2929
|
Body: retryPrompt,
|
package/dist/cli-metadata.js
CHANGED
package/dist/index.js
CHANGED
package/dist/setup-entry.js
CHANGED