@ykurilov/agent-chat-core 0.76.0 → 0.77.0
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/CHANGELOG.md +12 -0
- package/dist/{chunk-6KHSUGHE.js → chunk-BQTUOC3T.js} +56 -1
- package/dist/chunk-BQTUOC3T.js.map +1 -0
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/storage-contract.js +1 -1
- package/dist/types/app-state/app-state.d.ts +3 -1
- package/dist/types/app-state/flow-state-commit.d.ts +22 -0
- package/dist/types/app-state/state-changed.d.ts +1 -1
- package/dist/types/index.d.ts +3 -0
- package/package.json +1 -1
- package/dist/chunk-6KHSUGHE.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @ykurilov/agent-chat-core
|
|
2
2
|
|
|
3
|
+
## 0.77.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- f4c13da: Сценарий может сохранить подтверждённую судьёй веху отдельно от перехода и потребовать её вместе с актуальным вопросом человека. Например, публикация своего приложения больше не забывается после шести реплик, а старый интерес к курсу не запускает переход при поздней публикации.
|
|
8
|
+
|
|
9
|
+
Серверные `confirmations` и `exitGuards` включаются по желанию. Квитанция привязана к человеку, чату, сценарию, ветке и revision критерия; модельные факты её не устанавливают. Поля `flow.confirmations`, `flow.confirmationCheck` и `flow.checkedTransition` защищены от записи и удаления через `model.state`, включая замену родительского `flow`. `revokeConfirmation` позволяет backend исправить атрибуцию. Положительная проверка и решение сохраняются вместе до перехода с защитой от устаревших записей и повторов. Стабильные инструкции и инструменты модели не меняются.
|
|
10
|
+
|
|
11
|
+
`previewMigration` и опция `requiresConfirmation` у `migrateChats` оставляют разговоры без подходящей квитанции на прежней версии. Старый путь или поле карточки не считаются доказательством. Увеличения контекста судьи, автоматической проверки владения доменом и изменений JSON редактора нет.
|
|
12
|
+
|
|
13
|
+
Подключение, отмена, миграция и ограничения: [docs/flow-confirmations.md](../../docs/flow-confirmations.md). Без новых опций поведение прежнее; SQL-миграций нет. Приложение обрабатывает `busy`/`stale` при отмене и само определяет доверенный маршрут исправления атрибуции.
|
|
14
|
+
|
|
3
15
|
## 0.76.0
|
|
4
16
|
|
|
5
17
|
No changes in this release.
|
|
@@ -258,6 +258,13 @@ function createAppStateWriter(context) {
|
|
|
258
258
|
return keys;
|
|
259
259
|
}
|
|
260
260
|
function commit(record, next) {
|
|
261
|
+
if (!context.serverFlowChecks) {
|
|
262
|
+
for (const field of ["confirmations", "confirmationCheck", "checkedTransition"]) {
|
|
263
|
+
if (JSON.stringify(valueAt(current, ["flow", field])) !== JSON.stringify(valueAt(next, ["flow", field]))) {
|
|
264
|
+
throw new TypeError(`state: flow.${field} \u2014 \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u043D\u043E\u0439 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 SDK; \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442 \u043C\u043E\u0434\u0435\u043B\u0438 \u043D\u0435 \u043C\u0435\u043D\u044F\u0435\u0442 \u0438 \u043D\u0435 \u0443\u0434\u0430\u043B\u044F\u0435\u0442 \u0435\u0433\u043E`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
261
268
|
context.write(record);
|
|
262
269
|
current = next;
|
|
263
270
|
}
|
|
@@ -10022,6 +10029,15 @@ async function callWithRetries2(handler, input, timeoutMs, attempts) {
|
|
|
10022
10029
|
}
|
|
10023
10030
|
}
|
|
10024
10031
|
|
|
10032
|
+
// src/app-state/flow-state-commit.ts
|
|
10033
|
+
var ports = /* @__PURE__ */ new WeakMap();
|
|
10034
|
+
function registerFlowStateCommit(service, commit) {
|
|
10035
|
+
ports.set(service, commit);
|
|
10036
|
+
}
|
|
10037
|
+
function flowStateCommitter(service) {
|
|
10038
|
+
return ports.get(service);
|
|
10039
|
+
}
|
|
10040
|
+
|
|
10025
10041
|
// src/agent-run/reply-check-types.ts
|
|
10026
10042
|
var DEFAULT_REPLY_CHECKS_WEB = "replace";
|
|
10027
10043
|
function resolveReplyChecks(setting) {
|
|
@@ -12552,6 +12568,7 @@ function checkedResult(result, state, chatId) {
|
|
|
12552
12568
|
const records = [];
|
|
12553
12569
|
const writer = createAppStateWriter({
|
|
12554
12570
|
base: state,
|
|
12571
|
+
serverFlowChecks: true,
|
|
12555
12572
|
write: (record) => records.push(record),
|
|
12556
12573
|
logError: () => {
|
|
12557
12574
|
},
|
|
@@ -14906,6 +14923,43 @@ function createChatService(input) {
|
|
|
14906
14923
|
};
|
|
14907
14924
|
}
|
|
14908
14925
|
abandonedBurstReceivers.set(service, receivingAbandonedBurst);
|
|
14926
|
+
registerFlowStateCommit(service, async (input2) => {
|
|
14927
|
+
if (![input2.flowId, input2.revision].every((value) => typeof value === "string" && value.trim().length > 0 && value.length <= 200)) throw new TypeError("flow commit: flowId/revision \u2014 \u043D\u0435\u043F\u0443\u0441\u0442\u044B\u0435 \u0441\u0442\u0440\u043E\u043A\u0438 \u0434\u043E 200 \u0437\u043D\u0430\u043A\u043E\u0432");
|
|
14928
|
+
if (typeof input2.idempotencyKey !== "string" || !input2.idempotencyKey.trim() || input2.idempotencyKey.length > 200) {
|
|
14929
|
+
throw new TypeError("flow commit: idempotencyKey \u2014 \u043D\u0435\u043F\u0443\u0441\u0442\u0430\u044F \u0441\u0442\u0440\u043E\u043A\u0430 \u0434\u043E 200 \u0437\u043D\u0430\u043A\u043E\u0432");
|
|
14930
|
+
}
|
|
14931
|
+
if (!input2.flow || typeof input2.flow !== "object" || Array.isArray(input2.flow)) throw new TypeError("flow commit: flow \u2014 JSON-\u043E\u0431\u044A\u0435\u043A\u0442");
|
|
14932
|
+
const chat = await storage.getChat(input2.chatId);
|
|
14933
|
+
if (!chat || chat.ownerId !== input2.ownerId || deleting.has(input2.chatId)) return { status: "not_found" };
|
|
14934
|
+
if (closing) return { status: "busy" };
|
|
14935
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(JSON.stringify([input2.ownerId, input2.chatId, input2.flowId, input2.revision, input2.idempotencyKey])));
|
|
14936
|
+
const operationId = `flow-state:${Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
|
|
14937
|
+
try {
|
|
14938
|
+
return await whileStarting(input2.chatId, async () => {
|
|
14939
|
+
const { branch } = await loadTree(input2.chatId);
|
|
14940
|
+
const before = foldAppState(branch);
|
|
14941
|
+
const writer = createAppStateWriter({ base: before, write: () => {
|
|
14942
|
+
}, logError, chatId: input2.chatId, serverFlowChecks: true });
|
|
14943
|
+
writer.set("flow", input2.flow);
|
|
14944
|
+
writer.close();
|
|
14945
|
+
const record = { set: { flow: writer.values().flow } };
|
|
14946
|
+
const earlier = await storage.getMessage(operationId);
|
|
14947
|
+
if (earlier) {
|
|
14948
|
+
if (JSON.stringify(earlier.parts) !== JSON.stringify([appStatePart(record)])) throw new TypeError("flow commit: idempotencyKey \u0443\u0436\u0435 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D \u0441 \u0434\u0440\u0443\u0433\u0438\u043C payload");
|
|
14949
|
+
return branch.at(-1)?.id === operationId ? { status: "same", atMessageId: operationId } : { status: "stale" };
|
|
14950
|
+
}
|
|
14951
|
+
const head = branch.at(-1)?.id ?? null;
|
|
14952
|
+
if (head !== input2.expectedAtMessageId) return { status: "stale" };
|
|
14953
|
+
const message = stateMessage({ chatId: input2.chatId, parentId: head, record });
|
|
14954
|
+
await storage.insertMessage({ ...message, id: operationId });
|
|
14955
|
+
await branchChanged(input2.ownerId, input2.chatId, "flowCommit", before);
|
|
14956
|
+
return { status: "applied", atMessageId: operationId };
|
|
14957
|
+
});
|
|
14958
|
+
} catch (error) {
|
|
14959
|
+
if (error instanceof ChatBusyError) return { status: "busy" };
|
|
14960
|
+
throw error;
|
|
14961
|
+
}
|
|
14962
|
+
});
|
|
14909
14963
|
return service;
|
|
14910
14964
|
function isDetachedAnswer(last, runningId) {
|
|
14911
14965
|
return runningId === null && last?.status === "streaming" && !liveAnswerIds.has(last.id);
|
|
@@ -15135,6 +15189,7 @@ export {
|
|
|
15135
15189
|
DEFAULT_AFTER_TURN_ATTEMPTS,
|
|
15136
15190
|
DEFAULT_STATE_CHANGED_TIMEOUT_MS,
|
|
15137
15191
|
DEFAULT_STATE_CHANGED_ATTEMPTS,
|
|
15192
|
+
flowStateCommitter,
|
|
15138
15193
|
DEFAULT_REPLY_CHECKS_WEB,
|
|
15139
15194
|
resolveReplyChecks,
|
|
15140
15195
|
THOUGHT_TITLE_USAGE_SOURCE,
|
|
@@ -15182,4 +15237,4 @@ export {
|
|
|
15182
15237
|
InvalidWidgetAnswerError,
|
|
15183
15238
|
createChatService
|
|
15184
15239
|
};
|
|
15185
|
-
//# sourceMappingURL=chunk-
|
|
15240
|
+
//# sourceMappingURL=chunk-BQTUOC3T.js.map
|