@ykurilov/agent-chat-core 0.79.1 → 0.80.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/CHANGELOG.md +18 -0
- package/README.md +1 -0
- package/dist/{chunk-AJSRGBVM.js → chunk-PORXDIWX.js} +80 -31
- package/dist/chunk-PORXDIWX.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/storage-contract.js +1 -1
- package/dist/types/agent-run/build-model-request.d.ts +3 -9
- package/dist/types/agent-run/run-agent-turn.d.ts +2 -1
- package/dist/types/chat-service.d.ts +3 -1
- package/dist/types/compaction/run-compaction.d.ts +4 -0
- package/dist/types/compaction/summary-part.d.ts +10 -0
- package/dist/types/frozen-context/context-blocks.d.ts +6 -1
- package/dist/types/frozen-context/freeze-context.d.ts +2 -0
- package/dist/types/frozen-context/frozen-context-messages.d.ts +8 -2
- package/dist/types/index.d.ts +1 -1
- package/package.json +1 -1
- package/dist/chunk-AJSRGBVM.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @ykurilov/agent-chat-core
|
|
2
2
|
|
|
3
|
+
## 0.80.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- d59ae4e: После сжатия истории в режиме `contextBlocksRefresh: "history-start"` полный свежий снимок приложения размещается рядом со сводкой. Старые снимки оставленного хвоста больше не возвращают устаревшие данные; последующие изменения идут от свежей базы. Ошибка источника сохраняет прежний fallback, успешный пустой снимок тоже учитывается. Дата, память, место и notices не переносятся; сохранённые ответы не переписываются.
|
|
8
|
+
|
|
9
|
+
Запрос сжатия использует тот же сборщик frozen context, что и обычный ход, с исключением личных app-блоков, памяти, даты и места из сохраняемой сводки. Задание пересказа уточняет границу сжимаемой части. Настройки рассуждений провайдера не меняются. Обновить все пакеты одной версией; SQL-миграций и новых настроек нет.
|
|
10
|
+
|
|
11
|
+
## 0.80.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- 2cc8429: Добавлена серверная настройка `agent.contextBlocksRefresh: "history-start"`: блоки приложения читаются при первом снимке и после смены начала видимой истории, используя существующий frozen context ветки. Между этими событиями источник не вызывается и изменённые данные приложения не досылаются модели. По умолчанию и при `"turn"` поведение прежнее. Перезапуск и ветки используют сохранённый снимок; продолжение с выполненными шагами сохраняет frozen context. Retry без завершённых шагов создаёт новый ответ и может заново прочитать источник. Ошибка источника сохраняет fallback и оставляет следующей новой сборке повторную попытку.
|
|
16
|
+
|
|
17
|
+
### Как обновить приложение
|
|
18
|
+
|
|
19
|
+
Обновите установленные пакеты SDK одной версией. Если профиль должен застывать как память, добавьте `contextBlocksRefresh: "history-start"` рядом с `contextBlocks`. Изменения вне переписки передавайте через `prepareTurn.notices`; права по-прежнему проверяйте сервером. Для классификации каждого вопроса оставьте `"turn"`. Никаких SQL-миграций или собственного кэша не требуется. [Триггеры, ограничения и пример](https://github.com/ykurilov/agent-chat-sdk/blob/main/docs/context-blocks-refresh.md).
|
|
20
|
+
|
|
3
21
|
## 0.79.1
|
|
4
22
|
|
|
5
23
|
No changes in this release.
|
package/README.md
CHANGED
|
@@ -78,6 +78,7 @@ import type { ChatStorage } from "@ykurilov/agent-chat-core";
|
|
|
78
78
|
- Снимок перед каждым шагом: `agent.stepContext: ({ state, stepNumber, chat, subject, … }) => string | null` — текст ложится сообщением человека в самый конец запроса шага, после результатов инструментов, в историю не пишется. Снимок на шаге один, всё до него от шага к шагу те же байты (кэш модели). `null` — шаг без снимка, бросок — без снимка и строка в журнал. Функция видит те же `channel`, `audience`, `staff`, что инструменты (в группе личного не показывайте), данные чата — копиями. Срок `agent.stepContextTimeoutMs` (по умолчанию 5 с): не ответила — шаг без снимка, `abortSignal` отменён. Типы `StepContext`, `StepContextInput`.
|
|
79
79
|
- Застывающий контекст: память, сегодняшняя дата, место на экране и блоки приложения вписываются в вопрос человека один раз за ход и дальше не меняются ни на байт. Следующий ход побайтно начинается с последнего шага прошлого (с рассуждениями и инструментами), поэтому всё прошлое читается из кэша модели. В новый вопрос идут только изменившиеся блоки и строка `[Больше не действует: «ключ»]` про пропавшие. Источник может вернуть `{ key, hidden: true }` — блок есть, но не показан ради места: вместо «больше не действует» модель, видевшая его, получит `[Не показано ради места, но по-прежнему действует: «ключ»]`. Набор хода хранится служебной частью ответа `data-frozen-context` (`FROZEN_CONTEXT_PART_TYPE`): в поток, историю, `afterTurn` и поиск по истории она не уходит. Продолжение после подтверждения, автопродолжение, запасной провайдер и «Повторить» берут блоки из ответа и источники заново не опрашивают. Память строже остальных блоков: читается один раз на чат — в первом ходе, после сжатия истории, при смене начала истории (правка первого сообщения, «Переделать» первого ответа), в первом личном ходе после группового и после сбоя чтения — и в идущем чате не перечитывается и не досылается (ни изменения, ни новые записи, ни «Больше не действует»); `snapshot()` и `blocks()` в остальных ходах не зовутся. Своя долгая память может отдавать блоки по записям: `LongTermMemory.blocks?({ userId, chatId })`; без него — один блок из `snapshot()`.
|
|
80
80
|
- Блоки приложения в вопросе хода: `agent.contextBlocks: ({ chatId, ownerId, chat, state, subject, channel, audience, … }) => [{ key, text, private? }] | null` — список скиллов, роль, правила. Зовётся один раз в начале хода; текст вписывается в вопрос после памяти и даты и дальше не меняется ни на байт (кэш модели), ядро его не оборачивает. На следующих ходах в вопрос идут только изменённые блоки целиком и строка `[Больше не действует: «ключ»]` про убранные. Ключи `memory`, `memory:*`, `today`, `screen_place` заняты ядром: такой блок отбрасывается со строкой в журнал. `private: true` — в групповом ходе блок не показывается. Срок `agent.contextBlocksTimeoutMs` (по умолчанию 5 с; 0 или `Infinity` — без срока, иначе от 1000): не ответила или бросила — блоки приложения берутся из прошлого ответа, в журнал строка `[блоки контекста] …`, `abortSignal` отменён; «Стоп» — без строки. Блоки хранятся служебной частью ответа: в потоке, истории, `afterTurn` и поиске по истории её нет. Типы `ContextBlock`, `ContextBlocksInput`, `ContextBlocksSource`, `HiddenContextBlock`, `ContextBlockEntry`.
|
|
81
|
+
- `agent.contextBlocksRefresh: "history-start"` включает снимок приложения до смены начала видимой истории, как у памяти. Без настройки и при `"turn"` источник по-прежнему читается каждый новый ход. Снимок хранится в frozen context ветки; своего кэша или SQL-миграций не требуется. Изменения вне переписки передаются через `prepareTurn.notices`, права проверяются сервером. [Триггеры, ошибки и пример](https://github.com/ykurilov/agent-chat-sdk/blob/main/docs/context-blocks-refresh.md).
|
|
81
82
|
- Конец хода сразу после инструмента: `execute` возвращает `endTurn(output, { text? })` — модель следующего шага не делает, готовый `text` идёт в ответ обычной текстовой частью без запроса к провайдеру и без расхода; `output` модель и запись видят как обычно. Тип `EndTurnOptions`. С `endTurn(output, { requireText: true })` остановка принимается только при непустом пользовательском text-part текущего ответа; без него результат обычный и модель продолжает. Проверка в памяти потока, без чтения БД/flush. Пробелы и чисто форматные невидимые Unicode, reasoning, tool output, ошибки и прежняя история не считаются; Markdown/HTML по смыслу не разбирается. Явный непустой `options.text` сохраняет приоритет и прежний путь готового текста. Это не автоподтверждение и не гарантия ответа при отмене, лимите или сбое. [Полная семантика и переход](../../docs/in-product-agent.md#14-конец-хода-сразу-после-инструмента).
|
|
82
83
|
- Данные чата без записи: `service.getChatData(userId, chatId)` — копия, проверки владения как у `updateChatData`.
|
|
83
84
|
- Проверка ответа виджета на сервере: `checkAnswer(answer, ctx)` у своего виджета и общая `agent.widgets.checkAnswer(call, answer, ctx)` (для всех виджетов без своей). Зовётся после схемы под замком чата. Исход: `undefined` — принять, `{ answer }` — принять с заменой, `{ refuse: "текст" }` — отказать (`WidgetAnswerRefusedError`, сервер — 409 `widget_answer_refused`, виджет остаётся открытым). `ctx` — `ownerId`, `chatId`, `messageId`, `toolName`, `toolCallId`, `input`, `subject?`, `chatData?`, `state` (записи ложатся в ответ вместе с результатом виджета, хук `onStateChanged` — с причиной `widgetAnswer`), `emitAppEvent` (событие приложения вместе с ответом виджета), `signal` (отмена по сроку или «Стопу»: приложение слушает его само). Срок — `agent.widgets.checkAnswerTimeoutMs` (5 000 мс, заметно меньше `requestTimeoutMs` страницы). Исключение — 500, ничего не записано, в журнале только имя ошибки; срок вышел — `WidgetAnswerCheckTimeoutError`, сервер — 504 `widget_check_timeout`. Чат закрыли во время проверки — `ChatClosedError`, ответ не пишется.
|
|
@@ -4656,6 +4656,11 @@ function withStaffRepliesJoined(history) {
|
|
|
4656
4656
|
return changed ? joined : history;
|
|
4657
4657
|
}
|
|
4658
4658
|
|
|
4659
|
+
// src/compaction/summary-part.ts
|
|
4660
|
+
var SUMMARY = /* @__PURE__ */ Symbol("compaction-summary");
|
|
4661
|
+
var summaryPart = (text) => ({ type: "text", text, [SUMMARY]: true });
|
|
4662
|
+
var isSummaryPart = (part) => part[SUMMARY] === true;
|
|
4663
|
+
|
|
4659
4664
|
// src/frozen-context/frozen-context-messages.ts
|
|
4660
4665
|
function frozenContextBase(history) {
|
|
4661
4666
|
for (let index = history.length - 1; index >= 0; index -= 1) {
|
|
@@ -4670,6 +4675,11 @@ var RESUME_NOTE_ID = "frozen-context-note-";
|
|
|
4670
4675
|
function withFrozenContext(history, options2) {
|
|
4671
4676
|
const { current, group } = options2;
|
|
4672
4677
|
const dataOf = (message) => message.role !== "assistant" ? void 0 : current && message.id === current.answerId ? current.data : frozenContextOf(message.parts);
|
|
4678
|
+
const root = history[0];
|
|
4679
|
+
const anchorHistory = options2.anchorHistory && options2.anchorHistory[0]?.id === root?.id ? options2.anchorHistory : history;
|
|
4680
|
+
const allowed = options2.includeKey ?? (() => true);
|
|
4681
|
+
const anchor = root?.parts.some(isSummaryPart) ? anchorHistory.flatMap((message) => message.role === "assistant" ? [dataOf(message), ...message.parts.filter((p) => p.type === FROZEN_CONTEXT_PART_TYPE).slice(1).map((p) => p.data)] : []).concat(current?.data).find((data) => data?.appContextFrom === root.id) : void 0;
|
|
4682
|
+
let anchored = false;
|
|
4673
4683
|
const seen = /* @__PURE__ */ new Map();
|
|
4674
4684
|
const output = [];
|
|
4675
4685
|
const place = (texts) => {
|
|
@@ -4679,22 +4689,28 @@ function withFrozenContext(history, options2) {
|
|
|
4679
4689
|
if (last?.role === "user") output[output.length - 1] = { ...last, parts: [...last.parts, ...parts] };
|
|
4680
4690
|
else output.push({ id: `frozen-context-${output.length}`, role: "user", parts: output.length === 0 ? [{ type: "text", text: GREETING_LEAD }, ...parts] : parts });
|
|
4681
4691
|
};
|
|
4682
|
-
const textsOf = (data
|
|
4692
|
+
const textsOf = (data, base) => {
|
|
4693
|
+
const include = (key) => allowed(key) && (!anchor || anchored || isReservedKey(key));
|
|
4694
|
+
const texts = blockTexts(data, base, group, anchor || options2.includeKey ? include : void 0);
|
|
4695
|
+
if (data === anchor) anchored = true;
|
|
4696
|
+
return texts;
|
|
4697
|
+
};
|
|
4683
4698
|
let currentPlaced = false;
|
|
4684
4699
|
for (const message of history) {
|
|
4685
4700
|
const data = dataOf(message);
|
|
4686
4701
|
if (data) {
|
|
4687
|
-
place(textsOf(data));
|
|
4702
|
+
place(textsOf(data, data.base === null ? void 0 : seen.get(data.base)));
|
|
4688
4703
|
seen.set(message.id, data);
|
|
4689
4704
|
if (message.id === current?.answerId) currentPlaced = true;
|
|
4690
4705
|
}
|
|
4691
|
-
|
|
4692
|
-
|
|
4706
|
+
const placed = anchor && message === root ? { ...message, parts: message.parts.flatMap((part) => isSummaryPart(part) ? [part, ...anchor.blocks.filter((block) => !isReservedKey(block.key) && allowed(block.key) && !(group && block.private)).map((block) => ({ type: "text", text: block.text }))] : [part]) } : message;
|
|
4707
|
+
output.push(...withResumeNotes(placed, (note) => {
|
|
4708
|
+
const texts = textsOf(note, seen.get(message.id));
|
|
4693
4709
|
seen.set(message.id, note);
|
|
4694
4710
|
return texts;
|
|
4695
4711
|
}));
|
|
4696
4712
|
}
|
|
4697
|
-
if (current && !currentPlaced) place(textsOf(current.data));
|
|
4713
|
+
if (current && !currentPlaced) place(textsOf(current.data, current.data.base === null ? void 0 : seen.get(current.data.base)));
|
|
4698
4714
|
return output;
|
|
4699
4715
|
}
|
|
4700
4716
|
function withResumeNotes(message, textsOf) {
|
|
@@ -4724,11 +4740,11 @@ function holdNoteAfterApprovals(messages) {
|
|
|
4724
4740
|
return { messages: messages.slice(0, -1), note };
|
|
4725
4741
|
}
|
|
4726
4742
|
var awaitsApprovedRun = (part) => part.state === "approval-responded";
|
|
4727
|
-
function blockTexts(data, base, group) {
|
|
4728
|
-
return [...changedBlockTexts(data, base, group), ...(data.notices ?? []).map(noticeText)];
|
|
4743
|
+
function blockTexts(data, base, group, include) {
|
|
4744
|
+
return [...changedBlockTexts(data, base, group, include), ...(data.notices ?? []).map(noticeText)];
|
|
4729
4745
|
}
|
|
4730
|
-
function changedBlockTexts(data, base, group) {
|
|
4731
|
-
const shown = (block) => !(group && block.private);
|
|
4746
|
+
function changedBlockTexts(data, base, group, include) {
|
|
4747
|
+
const shown = (block) => (!include || include(block.key)) && !(group && block.private);
|
|
4732
4748
|
if (data.sent === "all" || !base) return data.blocks.filter(shown).map((block) => block.text);
|
|
4733
4749
|
const now = new Map(data.blocks.map((block) => [block.key, block]));
|
|
4734
4750
|
const before = new Map(base.blocks.map((block) => [block.key, block]));
|
|
@@ -4736,7 +4752,7 @@ function changedBlockTexts(data, base, group) {
|
|
|
4736
4752
|
const block = now.get(key);
|
|
4737
4753
|
return block && shown(block) ? [block.text] : [];
|
|
4738
4754
|
});
|
|
4739
|
-
const visibleKeys = (keys) => keys.filter((key) => !(group && (before.get(key)?.private ?? isMemoryKey(key))));
|
|
4755
|
+
const visibleKeys = (keys) => keys.filter((key) => (!include || include(key)) && !(group && (before.get(key)?.private ?? isMemoryKey(key))));
|
|
4740
4756
|
const removed = visibleKeys(data.sent.removed);
|
|
4741
4757
|
if (removed.length > 0) texts.push(noLongerValid(removed));
|
|
4742
4758
|
const hidden = visibleKeys(data.sent.hidden ?? []);
|
|
@@ -5106,7 +5122,10 @@ async function buildModelRequest(input) {
|
|
|
5106
5122
|
const cleaned = sendableHistory(input.serviceBlocks ? withoutForgedBlocks(untitled, input.serviceBlocks) : untitled);
|
|
5107
5123
|
const sendable = input.switchableTools ? withSwitchedOffCallsAsText(cleaned, input.switchableTools, tools) : cleaned;
|
|
5108
5124
|
const noted = withStaffRepliesJoined(withChannelNotes(withModeNotes(withBurstsJoined(withCorrectionsJoined(sendable)), input.modeNotes)));
|
|
5109
|
-
const held = input.frozenContext ? holdNoteAfterApprovals(withFrozenContext(noted,
|
|
5125
|
+
const held = input.frozenContext ? holdNoteAfterApprovals(withFrozenContext(noted, {
|
|
5126
|
+
...input.frozenContext,
|
|
5127
|
+
...input.frozenContext.anchorHistory && { anchorHistory: sendableHistory(input.frozenContext.anchorHistory) }
|
|
5128
|
+
})) : { messages: noted };
|
|
5110
5129
|
const history = selectReasoningForModel(held.messages, {
|
|
5111
5130
|
modelId: profile.id,
|
|
5112
5131
|
providerId: provider.id,
|
|
@@ -6918,25 +6937,29 @@ function appBlocksSource(options2) {
|
|
|
6918
6937
|
// src/frozen-context/freeze-context.ts
|
|
6919
6938
|
var sourceOf = (key) => isMemoryKey(key) ? "memory" : isReservedKey(key) ? "core" : "app";
|
|
6920
6939
|
async function freezeContext(input) {
|
|
6921
|
-
const { chatId, sources, base, signal, memoryFrom } = input;
|
|
6940
|
+
const { chatId, sources, base, signal, memoryFrom, appContextFrom } = input;
|
|
6922
6941
|
const log = input.logError ?? console.error;
|
|
6923
6942
|
const fromBase = (source) => base?.data.blocks.filter((block) => sourceOf(block.key) === source) ?? [];
|
|
6924
|
-
const read = async (source, fetch) => {
|
|
6925
|
-
|
|
6943
|
+
const read = async (source, fetch, from) => {
|
|
6944
|
+
const previous = source === "memory" ? base?.data.memoryFrom : base?.data.appContextFrom;
|
|
6945
|
+
const kept = from !== void 0 && previous === from;
|
|
6946
|
+
if (kept || !fetch) return { blocks: fromBase(source), ...kept && { from } };
|
|
6926
6947
|
try {
|
|
6927
6948
|
const blocks2 = await fetch();
|
|
6928
6949
|
if (blocks2 !== null && blocks2 !== void 0 && !Array.isArray(blocks2)) throw new TypeError(`\u0436\u0434\u0451\u043C \u0441\u043F\u0438\u0441\u043E\u043A \u0431\u043B\u043E\u043A\u043E\u0432, \u0430 \u043F\u0440\u0438\u0448\u043B\u043E ${typeof blocks2}`);
|
|
6929
|
-
return { blocks: blocks2 ?? [],
|
|
6950
|
+
return { blocks: blocks2 ?? [], ...from !== void 0 && { from } };
|
|
6930
6951
|
} catch (error) {
|
|
6931
6952
|
if (!signal?.aborted) log(`[\u0431\u043B\u043E\u043A\u0438 \u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442\u0430] \u0447\u0430\u0442=${chatId} \u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A=${source} \u0441\u0431\u043E\u0439: ${error instanceof Error ? error.message : "\u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u0430\u044F \u043E\u0448\u0438\u0431\u043A\u0430"}; \u0431\u043B\u043E\u043A\u0438 \u0438\u0437 \u043F\u0440\u043E\u0448\u043B\u043E\u0433\u043E \u0445\u043E\u0434\u0430`);
|
|
6932
|
-
return { blocks: fromBase(source)
|
|
6953
|
+
return { blocks: fromBase(source) };
|
|
6933
6954
|
}
|
|
6934
6955
|
};
|
|
6935
|
-
const
|
|
6936
|
-
const [memoryRead, appRead] = await Promise.all([read("memory", memoryKept ? void 0 : sources.memory), read("app", sources.app)]);
|
|
6956
|
+
const [memoryRead, appRead] = await Promise.all([read("memory", sources.memory, memoryFrom), read("app", sources.app, appContextFrom)]);
|
|
6937
6957
|
const memory = memoryRead.blocks;
|
|
6938
6958
|
const app = appRead.blocks;
|
|
6939
|
-
const
|
|
6959
|
+
const marks = {
|
|
6960
|
+
...memoryRead.from !== void 0 && { memoryFrom: memoryRead.from },
|
|
6961
|
+
...appRead.from !== void 0 && { appContextFrom: appRead.from }
|
|
6962
|
+
};
|
|
6940
6963
|
const accepted = /* @__PURE__ */ new Set();
|
|
6941
6964
|
const hidden = /* @__PURE__ */ new Set();
|
|
6942
6965
|
const accept = (block, source) => {
|
|
@@ -6962,7 +6985,7 @@ async function freezeContext(input) {
|
|
|
6962
6985
|
accepted.add(SCREEN_PLACE_KEY);
|
|
6963
6986
|
blocks.push(...app.filter((block) => accept(block, "app")).map(copyBlock));
|
|
6964
6987
|
if (sources.place) blocks.push({ key: SCREEN_PLACE_KEY, text: sources.place });
|
|
6965
|
-
if (!base) return { blocks, sent: "all", base: null, ...
|
|
6988
|
+
if (!base) return { blocks, sent: "all", base: null, ...marks };
|
|
6966
6989
|
const before = new Map(base.data.blocks.map((block) => [block.key, block.text]));
|
|
6967
6990
|
const keys = new Set(blocks.map((block) => block.key));
|
|
6968
6991
|
const gone = base.data.blocks.filter((block) => !keys.has(block.key)).map((block) => block.key);
|
|
@@ -6975,7 +6998,7 @@ async function freezeContext(input) {
|
|
|
6975
6998
|
...hiddenNow.length > 0 && { hidden: hiddenNow }
|
|
6976
6999
|
},
|
|
6977
7000
|
base: base.id,
|
|
6978
|
-
...
|
|
7001
|
+
...marks
|
|
6979
7002
|
};
|
|
6980
7003
|
}
|
|
6981
7004
|
function copyBlock(block) {
|
|
@@ -6993,7 +7016,7 @@ async function resumeNoteForTurn(input, turn) {
|
|
|
6993
7016
|
if (!seen) return void 0;
|
|
6994
7017
|
const place = input.samePlace ? seen.blocks.find((block) => block.key === SCREEN_PLACE_KEY)?.text ?? null : screenPlaceBlock(input.place);
|
|
6995
7018
|
const note = await freezeTurnContext(input, turn, { id: turn.answer.id, data: seen }, place);
|
|
6996
|
-
return hasNewBlocks(note) ? note : void 0;
|
|
7019
|
+
return hasNewBlocks(note) || note.appContextFrom !== seen.appContextFrom ? note : void 0;
|
|
6997
7020
|
}
|
|
6998
7021
|
async function freezeTurnContext(input, turn, base, place) {
|
|
6999
7022
|
const sources = {
|
|
@@ -7027,11 +7050,13 @@ async function freezeTurnContext(input, turn, base, place) {
|
|
|
7027
7050
|
}
|
|
7028
7051
|
});
|
|
7029
7052
|
}
|
|
7053
|
+
const historyStart = turn.history[0]?.id ?? input.messageId;
|
|
7030
7054
|
return freezeContext({
|
|
7031
7055
|
chatId: input.chatId,
|
|
7032
7056
|
sources,
|
|
7033
7057
|
// Начало видимой истории: то же — память из базы; после сжатия другое — память заново. Агент говорит первым — сам ответ.
|
|
7034
|
-
memoryFrom:
|
|
7058
|
+
memoryFrom: historyStart,
|
|
7059
|
+
...input.contextBlocksRefresh === "history-start" && { appContextFrom: historyStart },
|
|
7035
7060
|
base,
|
|
7036
7061
|
signal: input.abortSignal,
|
|
7037
7062
|
...input.logError && { logError: input.logError }
|
|
@@ -7232,7 +7257,17 @@ async function runTurn(turnInput, emitRaw) {
|
|
|
7232
7257
|
let resumeNote = resume && !resume.replay && !frozen.fresh ? await resumeNoteForTurn(input, { history: answer.request().history, answer: resume.message, state: publicAppState(appState.values()), ...viewer && { viewer } }) : void 0;
|
|
7233
7258
|
if (resume && turnNotices && !frozen.fresh) {
|
|
7234
7259
|
const seen = latestFrozenContextOf(resume.message.parts);
|
|
7235
|
-
if (seen)
|
|
7260
|
+
if (seen) {
|
|
7261
|
+
resumeNote = {
|
|
7262
|
+
...resumeNote ?? {
|
|
7263
|
+
blocks: seen.blocks,
|
|
7264
|
+
sent: { changed: [], removed: [] },
|
|
7265
|
+
base: messageId,
|
|
7266
|
+
...input.contextBlocksRefresh === "history-start" && seen.appContextFrom !== void 0 && { appContextFrom: seen.appContextFrom }
|
|
7267
|
+
},
|
|
7268
|
+
notices: turnNotices
|
|
7269
|
+
};
|
|
7270
|
+
}
|
|
7236
7271
|
}
|
|
7237
7272
|
const outages = input.providerOutages ?? createProviderOutages({ now: () => (input.now ?? (() => /* @__PURE__ */ new Date()))().getTime(), logError });
|
|
7238
7273
|
const allFallbackIds = fallbackProviders({
|
|
@@ -7843,6 +7878,7 @@ async function openAttempt(input, attempt, attemptSignal) {
|
|
|
7843
7878
|
stepContext,
|
|
7844
7879
|
stepContextTimeoutMs,
|
|
7845
7880
|
contextBlocks: _contextBlocks,
|
|
7881
|
+
contextBlocksRefresh: _contextBlocksRefresh,
|
|
7846
7882
|
contextBlocksTimeoutMs: _contextBlocksTimeoutMs,
|
|
7847
7883
|
...requestInput
|
|
7848
7884
|
} = input;
|
|
@@ -11560,7 +11596,7 @@ function tokens(count) {
|
|
|
11560
11596
|
}
|
|
11561
11597
|
function compactionTask(input) {
|
|
11562
11598
|
if (input.instruction !== void 0) return input.instruction;
|
|
11563
|
-
return `\u0421\u0434\u0435\u043B\u0430\u0439 \u0441\u0432\u043E\u0434\u043A\u0443 \
|
|
11599
|
+
return `\u0421\u0434\u0435\u043B\u0430\u0439 \u0441\u0432\u043E\u0434\u043A\u0443 \u0441\u0436\u0438\u043C\u0430\u0435\u043C\u043E\u0439 \u0447\u0430\u0441\u0442\u0438 \u043F\u0435\u0440\u0435\u043F\u0438\u0441\u043A\u0438 \u0432\u044B\u0448\u0435. \u041E\u043D\u0430 \u0437\u0430\u043A\u0430\u043D\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044F \u043D\u0430 \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0435\u043C \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0438 \u043F\u0435\u0440\u0435\u0434 \u044D\u0442\u0438\u043C \u0437\u0430\u0434\u0430\u043D\u0438\u0435\u043C; \u0431\u043E\u043B\u0435\u0435 \u043F\u043E\u0437\u0434\u043D\u044F\u044F \u043F\u0435\u0440\u0435\u043F\u0438\u0441\u043A\u0430 \u043E\u0441\u0442\u0430\u043D\u0435\u0442\u0441\u044F \u0432 \u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442\u0435 \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E. \u041F\u0435\u0440\u0435\u0441\u043A\u0430\u0437 \u0434\u043E\u043B\u0436\u0435\u043D \u043E\u0442\u0440\u0430\u0436\u0430\u0442\u044C \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 \u043D\u0430 \u044D\u0442\u043E\u0439 \u0433\u0440\u0430\u043D\u0438\u0446\u0435, \u0447\u0442\u043E\u0431\u044B \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u044C \u0440\u0430\u0437\u0433\u043E\u0432\u043E\u0440 \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u043D\u044B\u043C \u0445\u0432\u043E\u0441\u0442\u043E\u043C, \u0431\u0435\u0437 \u043F\u043E\u0432\u0442\u043E\u0440\u0435\u043D\u0438\u044F \u0443\u0436\u0435 \u0441\u0434\u0435\u043B\u0430\u043D\u043D\u043E\u0433\u043E \u0432 \u043D\u0451\u043C.
|
|
11564
11600
|
|
|
11565
11601
|
\u0415\u0441\u043B\u0438 \u0432 \u043D\u0430\u0447\u0430\u043B\u0435 \u043F\u0435\u0440\u0435\u043F\u0438\u0441\u043A\u0438 \u0443\u0436\u0435 \u0435\u0441\u0442\u044C \u0441\u0432\u043E\u0434\u043A\u0430, \u043D\u0435 \u0434\u043E\u043F\u0438\u0441\u044B\u0432\u0430\u0439 \u043A \u043D\u0435\u0439, \u0430 \u043F\u0435\u0440\u0435\u043F\u0438\u0448\u0438 \u0435\u0451 \u0446\u0435\u043B\u0438\u043A\u043E\u043C \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \u043D\u043E\u0432\u044B\u043C\u0438 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F\u043C\u0438: \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u0441\u044F \u043E\u0434\u043D\u0430 \u0441\u0432\u043E\u0434\u043A\u0430.
|
|
11566
11602
|
|
|
@@ -11591,10 +11627,10 @@ ${summary}
|
|
|
11591
11627
|
function applyCompaction(branch, active) {
|
|
11592
11628
|
if (!active) return branch.map(toAgentChatMessage);
|
|
11593
11629
|
const tail = branch.slice(active.throughIndex + 1).map(toAgentChatMessage);
|
|
11594
|
-
const
|
|
11630
|
+
const summary = summaryPart(summaryFrame(active.record.summary));
|
|
11595
11631
|
const [first, ...rest] = tail;
|
|
11596
|
-
if (first?.role === "user") return [{ ...first, parts: [
|
|
11597
|
-
return [{ id: `${active.record.id}-summary`, role: "user", parts: [
|
|
11632
|
+
if (first?.role === "user") return [{ ...first, parts: [summary, ...first.parts] }, ...rest];
|
|
11633
|
+
return [{ id: `${active.record.id}-summary`, role: "user", parts: [summary] }, ...tail];
|
|
11598
11634
|
}
|
|
11599
11635
|
|
|
11600
11636
|
// src/compaction/run-compaction.ts
|
|
@@ -11626,6 +11662,13 @@ async function runCompaction(input) {
|
|
|
11626
11662
|
const request = await buildModelRequest({
|
|
11627
11663
|
...requestInput,
|
|
11628
11664
|
...input.model,
|
|
11665
|
+
// Общая сводка не несёт privacy-схему: только публичные app blocks, без памяти/даты/места.
|
|
11666
|
+
// Пересказ шагов остаётся на прежнем пути без frozen blocks; никакого нового private opt-in.
|
|
11667
|
+
...!input.transient && { frozenContext: {
|
|
11668
|
+
group: true,
|
|
11669
|
+
includeKey: (key) => !isReservedKey(key),
|
|
11670
|
+
...input.contextHistory && { anchorHistory: input.contextHistory }
|
|
11671
|
+
} },
|
|
11629
11672
|
// Бюджет рассуждений — от предела сводки, а не от потолка модели: иначе он больше предела.
|
|
11630
11673
|
maxOutputTokens,
|
|
11631
11674
|
...lowestLevel && { reasoning: lowestLevel },
|
|
@@ -11636,7 +11679,7 @@ async function runCompaction(input) {
|
|
|
11636
11679
|
role: "user",
|
|
11637
11680
|
content: input.task ?? compactionTask({ summaryCeilingTokens: settings.summaryCeilingTokens, instruction: settings.instruction })
|
|
11638
11681
|
};
|
|
11639
|
-
let base = [...request.messages, task];
|
|
11682
|
+
let base = [...request.messages, ...request.noteAfterApprovals ?? [], task];
|
|
11640
11683
|
let messages = base;
|
|
11641
11684
|
let summary = "";
|
|
11642
11685
|
let summaryTokens = 0;
|
|
@@ -11771,7 +11814,8 @@ function createCompactionService(options2) {
|
|
|
11771
11814
|
}
|
|
11772
11815
|
overflow?.onStart();
|
|
11773
11816
|
model = settings.model ?? model;
|
|
11774
|
-
const
|
|
11817
|
+
const active = activeCompaction(branch, compactions);
|
|
11818
|
+
const history = applyCompaction(branch.slice(0, plan.throughIndex + 1), active);
|
|
11775
11819
|
const chat = await storage.getChat(chatId);
|
|
11776
11820
|
const ownerId = chat?.ownerId ?? "";
|
|
11777
11821
|
const result = await runCompaction({
|
|
@@ -11784,6 +11828,7 @@ function createCompactionService(options2) {
|
|
|
11784
11828
|
...options2.switchableTools && { switchableTools: options2.switchableTools },
|
|
11785
11829
|
...observation(ownerId, answerId),
|
|
11786
11830
|
history,
|
|
11831
|
+
contextHistory: applyCompaction(branch, active),
|
|
11787
11832
|
...options2.attachments && { attachments: options2.attachments },
|
|
11788
11833
|
...options2.serviceBlocks && { serviceBlocks: options2.serviceBlocks },
|
|
11789
11834
|
settings,
|
|
@@ -11928,6 +11973,7 @@ function createCompactionService(options2) {
|
|
|
11928
11973
|
...options2.switchableTools && { switchableTools: options2.switchableTools },
|
|
11929
11974
|
...observation(ownerId, answerId),
|
|
11930
11975
|
history: [...history, { id: `${chatId}-answer-steps`, role: "assistant", parts: steps }],
|
|
11976
|
+
transient: true,
|
|
11931
11977
|
...options2.attachments && { attachments: options2.attachments },
|
|
11932
11978
|
...options2.serviceBlocks && { serviceBlocks: options2.serviceBlocks },
|
|
11933
11979
|
settings,
|
|
@@ -12904,6 +12950,9 @@ function createChatService(input) {
|
|
|
12904
12950
|
prepareTurn,
|
|
12905
12951
|
...agentSettings
|
|
12906
12952
|
} = options2.agent;
|
|
12953
|
+
if (agentSettings.contextBlocksRefresh !== void 0 && agentSettings.contextBlocksRefresh !== "turn" && agentSettings.contextBlocksRefresh !== "history-start") {
|
|
12954
|
+
throw new TypeError('agent.contextBlocksRefresh: \u0436\u0434\u0451\u043C "turn" \u0438\u043B\u0438 "history-start"');
|
|
12955
|
+
}
|
|
12907
12956
|
const stepContextTimeoutMs = resolveTimeoutMs(stepContextTimeoutSetting, DEFAULT_STEP_CONTEXT_TIMEOUT_MS, "agent.stepContextTimeoutMs");
|
|
12908
12957
|
const contextBlocksTimeoutMs = resolveTimeoutMs(contextBlocksTimeoutSetting, DEFAULT_CONTEXT_BLOCKS_TIMEOUT_MS, "agent.contextBlocksTimeoutMs");
|
|
12909
12958
|
const turnLimits = resolveTurnLimits({ turnTimeoutMs, maxOutputTokens }, options2.catalog);
|
|
@@ -15303,4 +15352,4 @@ export {
|
|
|
15303
15352
|
InvalidWidgetAnswerError,
|
|
15304
15353
|
createChatService
|
|
15305
15354
|
};
|
|
15306
|
-
//# sourceMappingURL=chunk-
|
|
15355
|
+
//# sourceMappingURL=chunk-PORXDIWX.js.map
|