@ykurilov/agent-chat-core 0.55.0 → 0.56.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 +17 -0
- package/dist/{chunk-PWW3R3VL.js → chunk-7M7M7DAN.js} +85 -14
- package/dist/chunk-7M7M7DAN.js.map +1 -0
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/storage-contract.js +3 -3
- package/dist/storage-contract.js.map +1 -1
- package/dist/types/agent-run/agent-viewer.d.ts +60 -0
- package/dist/types/agent-run/run-agent-turn.d.ts +8 -0
- package/dist/types/chat-service.d.ts +11 -0
- package/dist/types/compaction/compaction-service.d.ts +3 -0
- package/dist/types/conversation/types.d.ts +3 -1
- package/dist/types/frozen-context/context-blocks.d.ts +3 -0
- package/dist/types/frozen-context/turn-context.d.ts +3 -0
- package/dist/types/index.d.ts +2 -0
- package/package.json +1 -1
- package/dist/chunk-PWW3R3VL.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @ykurilov/agent-chat-core
|
|
2
2
|
|
|
3
|
+
## 0.56.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 24c313e: Новый пакет `@ykurilov/agent-chat-mcp`: серверы MCP, которые подключает админ приложения.
|
|
8
|
+
|
|
9
|
+
- `createMcpServers({ store, secretKey, isAdmin, proxy?, spending?, limits?, syncIntervalMs? })` → `mcp.tools(model, appTools?)`
|
|
10
|
+
для `agent.tools` (первым; при одинаковом имени побеждает инструмент приложения), `mcp.admin`, `mcp.reload()`, `mcp.sync()`, `mcp.close()`. «Только админы» — по `model.viewer.isAdmin`;
|
|
11
|
+
`isAdmin` (может быть асинхронной) — для экрана. Правка доходит до всех копий сервера по отметке версии в хранилище. Только удалённые серверы (Streamable HTTP, SSE). Инструменты — из
|
|
12
|
+
сохранённого снимка списка: запрос к модели стабилен, упавший сервер не ломает начало запроса. Соединение — на
|
|
13
|
+
проверенный адрес DNS; заголовки прокси — только на `proxy.origin`.
|
|
14
|
+
- `createMcpAdminHandler({ mcp, resolveUser, allowedOrigins })` — адреса `/api/mcp`, не админу 404.
|
|
15
|
+
- Хранилища: `createMemoryMcpStore`, `/sqlite` `createSqliteMcpStore`, `/postgres` `createPostgresMcpStore`; миграции сами.
|
|
16
|
+
- `/react`: `McpAdmin`, `useMcpAdmin`, договор скина `McpSkin` v1 (с формой правки `McpServerCardView.edit`), надписи ru/en. Скин Тандема: `./mcp` → `tandemMcpSkin`.
|
|
17
|
+
- Ядро: штатный вид расхода `mcp_tool`; `agent.viewer` — права человека раз в начале хода, полем `viewer` в
|
|
18
|
+
`contextBlocks` и `AgentToolsModel`. Песочница: права тестового чата — по владельцу чата. web-tools: наружу `dnsHostResolver`.
|
|
19
|
+
|
|
3
20
|
## 0.55.0
|
|
4
21
|
|
|
5
22
|
### Minor Changes
|
|
@@ -41,7 +41,8 @@ var BUILT_IN_USAGE_SOURCES = [
|
|
|
41
41
|
"judge",
|
|
42
42
|
"first_message",
|
|
43
43
|
"voice_input",
|
|
44
|
-
"voice_polish"
|
|
44
|
+
"voice_polish",
|
|
45
|
+
"mcp_tool"
|
|
45
46
|
];
|
|
46
47
|
|
|
47
48
|
// src/conversation/branches.ts
|
|
@@ -2284,6 +2285,57 @@ function jsonBytes(value) {
|
|
|
2284
2285
|
}
|
|
2285
2286
|
}
|
|
2286
2287
|
|
|
2288
|
+
// src/agent-run/agent-viewer.ts
|
|
2289
|
+
var AgentViewerError = class extends Error {
|
|
2290
|
+
constructor(message, options2) {
|
|
2291
|
+
super(message, options2);
|
|
2292
|
+
this.name = "AgentViewerError";
|
|
2293
|
+
}
|
|
2294
|
+
};
|
|
2295
|
+
async function resolveAgentViewer(source, input) {
|
|
2296
|
+
input.abortSignal.throwIfAborted();
|
|
2297
|
+
let viewer;
|
|
2298
|
+
try {
|
|
2299
|
+
viewer = await Promise.race([
|
|
2300
|
+
Promise.resolve().then(() => source(input)),
|
|
2301
|
+
new Promise((_, reject) => input.abortSignal.addEventListener("abort", () => reject(input.abortSignal.reason), { once: true }))
|
|
2302
|
+
]);
|
|
2303
|
+
} catch (error) {
|
|
2304
|
+
if (input.abortSignal.aborted) throw error;
|
|
2305
|
+
throw new AgentViewerError(`agent.viewer \u0431\u0440\u043E\u0441\u0438\u043B\u0430: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
2306
|
+
}
|
|
2307
|
+
if (typeof viewer !== "object" || viewer === null || Array.isArray(viewer)) throw new AgentViewerError("agent.viewer \u0432\u0435\u0440\u043D\u0443\u043B\u0430 \u043D\u0435 \u043E\u0431\u044A\u0435\u043A\u0442");
|
|
2308
|
+
return Object.freeze({ ...viewer });
|
|
2309
|
+
}
|
|
2310
|
+
function viewerInput(turn) {
|
|
2311
|
+
const ownerId = turn.ownerId ?? "";
|
|
2312
|
+
return {
|
|
2313
|
+
userId: turn.staff?.id ?? ownerId,
|
|
2314
|
+
chatId: turn.chatId,
|
|
2315
|
+
ownerId,
|
|
2316
|
+
messageId: turn.messageId,
|
|
2317
|
+
chat: structuredClone({ ...turn.chatData && { data: turn.chatData } }),
|
|
2318
|
+
...turn.subject && { subject: structuredClone(turn.subject) },
|
|
2319
|
+
channel: turn.channel ?? "web",
|
|
2320
|
+
audience: turn.audience,
|
|
2321
|
+
...turn.staff && { staff: structuredClone(turn.staff) },
|
|
2322
|
+
abortSignal: turn.abortSignal
|
|
2323
|
+
};
|
|
2324
|
+
}
|
|
2325
|
+
var VIEWER_OUTSIDE_TURN_TIMEOUT_MS = 1e4;
|
|
2326
|
+
async function resolveViewerOutsideTurn(source, turn, signal) {
|
|
2327
|
+
const deadline = new AbortController();
|
|
2328
|
+
const timer = setTimeout(
|
|
2329
|
+
() => deadline.abort(new AgentViewerError(`agent.viewer \u043D\u0435 \u043E\u0442\u0432\u0435\u0442\u0438\u043B\u0430 \u0437\u0430 ${VIEWER_OUTSIDE_TURN_TIMEOUT_MS / 1e3} \u0441`)),
|
|
2330
|
+
VIEWER_OUTSIDE_TURN_TIMEOUT_MS
|
|
2331
|
+
);
|
|
2332
|
+
try {
|
|
2333
|
+
return await resolveAgentViewer(source, viewerInput({ ...turn, abortSignal: signal ? AbortSignal.any([signal, deadline.signal]) : deadline.signal }));
|
|
2334
|
+
} finally {
|
|
2335
|
+
clearTimeout(timer);
|
|
2336
|
+
}
|
|
2337
|
+
}
|
|
2338
|
+
|
|
2287
2339
|
// src/helpers/run-helper.ts
|
|
2288
2340
|
import { generateText as generateText2, stepCountIs as stepCountIs2 } from "ai";
|
|
2289
2341
|
|
|
@@ -5436,6 +5488,7 @@ async function freezeTurnContext(input, turn, base, place) {
|
|
|
5436
5488
|
channel: input.channel ?? "web",
|
|
5437
5489
|
audience: input.group ? "group" : "private",
|
|
5438
5490
|
...input.staff && { staff: structuredClone(input.staff) },
|
|
5491
|
+
...turn.viewer && { viewer: turn.viewer },
|
|
5439
5492
|
modelId: input.modelId,
|
|
5440
5493
|
providerId: input.providerId
|
|
5441
5494
|
}
|
|
@@ -5577,10 +5630,12 @@ async function runTurn(turnInput, emitRaw) {
|
|
|
5577
5630
|
let errorKind;
|
|
5578
5631
|
let providerId = input.providerId;
|
|
5579
5632
|
let answeredProviderId = input.providerId;
|
|
5633
|
+
let viewer;
|
|
5580
5634
|
try {
|
|
5581
5635
|
const { history: historySource } = input;
|
|
5582
5636
|
const fullHistory = typeof historySource === "function" ? await historySource() : historySource;
|
|
5583
5637
|
const branchState = input.appState ?? foldAppState(fullHistory);
|
|
5638
|
+
viewer = input.viewer && await resolveAgentViewer(input.viewer, viewerInput({ ...input, audience: input.group ? "group" : "private" }));
|
|
5584
5639
|
const prepared = input.prepareTurn && await input.prepareTurn({ state: branchState, abortSignal: input.abortSignal });
|
|
5585
5640
|
const turnNotices = prepared && prepared.notices.length > 0 ? prepared.notices : void 0;
|
|
5586
5641
|
const stateBase = prepared?.state ?? branchState;
|
|
@@ -5596,10 +5651,11 @@ async function runTurn(turnInput, emitRaw) {
|
|
|
5596
5651
|
const frozenOfTurn = await frozenContextForTurn(input, {
|
|
5597
5652
|
history: answer.request().history,
|
|
5598
5653
|
answer: resume?.message ?? fullHistory.find((message) => message.id === messageId),
|
|
5599
|
-
state: publicAppState(appState.values())
|
|
5654
|
+
state: publicAppState(appState.values()),
|
|
5655
|
+
...viewer && { viewer }
|
|
5600
5656
|
});
|
|
5601
5657
|
const frozen = turnNotices && frozenOfTurn.fresh ? { ...frozenOfTurn, data: { ...frozenOfTurn.data, notices: turnNotices } } : frozenOfTurn;
|
|
5602
|
-
let resumeNote = resume && !resume.replay && !frozen.fresh ? await resumeNoteForTurn(input, { history: answer.request().history, answer: resume.message, state: publicAppState(appState.values()) }) : void 0;
|
|
5658
|
+
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;
|
|
5603
5659
|
if (resume && turnNotices && !frozen.fresh) {
|
|
5604
5660
|
const seen = latestFrozenContextOf(resume.message.parts);
|
|
5605
5661
|
if (seen) resumeNote = { ...resumeNote ?? { blocks: seen.blocks, sent: { changed: [], removed: [] }, base: messageId }, notices: turnNotices };
|
|
@@ -5629,7 +5685,7 @@ async function runTurn(turnInput, emitRaw) {
|
|
|
5629
5685
|
if (resume && !resume.replay) {
|
|
5630
5686
|
const continued = helpersToContinue(resume.message.parts);
|
|
5631
5687
|
if (continued.length > 0) {
|
|
5632
|
-
await continueHelpers(input, continued, { toolQueue, dataChanges, appEvents, chatClosure, appState, emit, logError });
|
|
5688
|
+
await continueHelpers(input, continued, { ...viewer && { viewer }, toolQueue, dataChanges, appEvents, chatClosure, appState, emit, logError });
|
|
5633
5689
|
const parts2 = await saver.snapshot();
|
|
5634
5690
|
answer.update(parts2, { modelId, providerId: answeredProviderId });
|
|
5635
5691
|
mainLoopWaits = input.abortSignal.aborted || pendingHumanInput(parts2, input.waitingWidgets).length > 0;
|
|
@@ -5671,6 +5727,7 @@ async function runTurn(turnInput, emitRaw) {
|
|
|
5671
5727
|
steps: { done: stepsDone, max: maxSteps, beforeResume: stepsBeforeResume },
|
|
5672
5728
|
historyRewritten,
|
|
5673
5729
|
frozenContext: frozen.data,
|
|
5730
|
+
...viewer && { viewer },
|
|
5674
5731
|
toolQueue,
|
|
5675
5732
|
endTurns,
|
|
5676
5733
|
browser,
|
|
@@ -5853,7 +5910,8 @@ async function runTurn(turnInput, emitRaw) {
|
|
|
5853
5910
|
}
|
|
5854
5911
|
} catch (error2) {
|
|
5855
5912
|
if (!input.abortSignal.aborted) {
|
|
5856
|
-
|
|
5913
|
+
if (error2 instanceof AgentViewerError) logError(`[agent.viewer] \u0447\u0430\u0442=${input.chatId} \u0445\u043E\u0434 \u043D\u0435 \u043D\u0430\u0447\u0430\u0442: ${error2.message}`);
|
|
5914
|
+
errorKind = error2 instanceof AgentViewerError ? "other" : classifyProviderError(error2, void 0);
|
|
5857
5915
|
errors = [{ type: "error", errorText: errorKind }];
|
|
5858
5916
|
}
|
|
5859
5917
|
}
|
|
@@ -6462,6 +6520,7 @@ function turnToolsModel(input, found, turn) {
|
|
|
6462
6520
|
...input.subject && { subject: input.subject },
|
|
6463
6521
|
chat: { ...input.chatData && { data: input.chatData } },
|
|
6464
6522
|
...input.staff && { staff: input.staff },
|
|
6523
|
+
...turn.viewer && { viewer: turn.viewer },
|
|
6465
6524
|
...input.closeChat && { closeChat: turn.chatClosure.request },
|
|
6466
6525
|
// Инструменту — только чтение и запись: конец записи и служебные ключи — дело ядра.
|
|
6467
6526
|
state: { get: turn.appState.get, set: turn.appState.set, unset: turn.appState.unset }
|
|
@@ -9717,7 +9776,7 @@ function createCompactionService(options2) {
|
|
|
9717
9776
|
chatId,
|
|
9718
9777
|
model,
|
|
9719
9778
|
instructions: await instructionsOf(chat),
|
|
9720
|
-
tools: resolveTools(model, chat, chatId, ownerId),
|
|
9779
|
+
tools: await resolveTools(model, chat, chatId, ownerId, branch, signal),
|
|
9721
9780
|
...options2.switchableTools && { switchableTools: options2.switchableTools },
|
|
9722
9781
|
...observation(ownerId, answerId),
|
|
9723
9782
|
history,
|
|
@@ -9764,19 +9823,26 @@ function createCompactionService(options2) {
|
|
|
9764
9823
|
function observation(ownerId, answerId) {
|
|
9765
9824
|
return options2.turnObserver ? { observe: { observer: options2.turnObserver, ownerId, messageId: answerId ?? null } } : {};
|
|
9766
9825
|
}
|
|
9767
|
-
function resolveTools(model, chat, chatId, ownerId) {
|
|
9768
|
-
const { tools } = options2.agent;
|
|
9826
|
+
async function resolveTools(model, chat, chatId, ownerId, branch, signal) {
|
|
9827
|
+
const { tools, viewer: viewerSource } = options2.agent;
|
|
9769
9828
|
if (typeof tools !== "function") return tools;
|
|
9770
9829
|
const subject = chat ? subjectOfChat(chat) : void 0;
|
|
9830
|
+
const chatData = chat ? chatDataOfInput(chat) : void 0;
|
|
9831
|
+
const { channel, group } = turnChannelOf(branch);
|
|
9832
|
+
const audience = group ? "group" : "private";
|
|
9833
|
+
const viewer = viewerSource && await resolveViewerOutsideTurn(viewerSource, { chatId, ownerId, messageId: "", ...chatData && { chatData }, ...subject && { subject }, channel, audience }, signal);
|
|
9771
9834
|
return tools({
|
|
9772
9835
|
profile: findModel(catalog, model.modelId, model.providerId).profile,
|
|
9773
9836
|
providerId: model.providerId,
|
|
9774
9837
|
chatId,
|
|
9775
9838
|
ownerId,
|
|
9776
9839
|
place: null,
|
|
9840
|
+
channel,
|
|
9841
|
+
audience,
|
|
9777
9842
|
notifyDataChanged: (change) => logError(`\u0418\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442 \u0441\u043E\u043E\u0431\u0449\u0438\u043B \u043E\u0431 \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0438 \u0434\u0430\u043D\u043D\u044B\u0445 \xAB${String(change?.tag)}\xBB \u0432\u043E \u0432\u0440\u0435\u043C\u044F \u0441\u0436\u0430\u0442\u0438\u044F \u0447\u0430\u0442\u0430 ${chatId}: \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u043D\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u043E`),
|
|
9778
9843
|
...subject && { subject },
|
|
9779
|
-
chat: { ...
|
|
9844
|
+
chat: { ...chatData && { data: chatData } },
|
|
9845
|
+
...viewer && { viewer }
|
|
9780
9846
|
});
|
|
9781
9847
|
}
|
|
9782
9848
|
return {
|
|
@@ -9853,7 +9919,7 @@ function createCompactionService(options2) {
|
|
|
9853
9919
|
chatId,
|
|
9854
9920
|
model,
|
|
9855
9921
|
instructions: await instructionsOf(chat),
|
|
9856
|
-
tools: resolveTools(model, chat, chatId, ownerId),
|
|
9922
|
+
tools: await resolveTools(model, chat, chatId, ownerId, history, abortSignal),
|
|
9857
9923
|
...options2.switchableTools && { switchableTools: options2.switchableTools },
|
|
9858
9924
|
...observation(ownerId, answerId),
|
|
9859
9925
|
history: [...history, { id: `${chatId}-answer-steps`, role: "assistant", parts: steps }],
|
|
@@ -12632,6 +12698,9 @@ function createChatService(input) {
|
|
|
12632
12698
|
const choice = effectiveChoiceOfChat(options2.catalog, env, chat, defaultChoice);
|
|
12633
12699
|
const found = findModel(options2.catalog, choice.modelId, choice.providerId);
|
|
12634
12700
|
const subject = subjectOfChat(chat);
|
|
12701
|
+
const { channel, group } = turnChannelOf(await loadCurrentBranch(storage, chatId));
|
|
12702
|
+
const audience = group ? "group" : "private";
|
|
12703
|
+
const viewer = options2.agent.viewer && await resolveViewerOutsideTurn(options2.agent.viewer, { chatId, ownerId, messageId: "", chatData: chatDataOfInput(chat), subject, channel, audience });
|
|
12635
12704
|
const model = {
|
|
12636
12705
|
profile: found.profile,
|
|
12637
12706
|
providerId: found.provider.id,
|
|
@@ -12641,11 +12710,12 @@ function createChatService(input) {
|
|
|
12641
12710
|
// Вкладки у фоновой задачи нет: сообщать об изменённых данных некому.
|
|
12642
12711
|
notifyDataChanged: () => {
|
|
12643
12712
|
},
|
|
12644
|
-
channel
|
|
12645
|
-
audience
|
|
12713
|
+
channel,
|
|
12714
|
+
audience,
|
|
12646
12715
|
messageId: "",
|
|
12647
12716
|
...subject && { subject },
|
|
12648
|
-
chat: { ...chatDataOfInput(chat) && { data: chatDataOfInput(chat) } }
|
|
12717
|
+
chat: { ...chatDataOfInput(chat) && { data: chatDataOfInput(chat) } },
|
|
12718
|
+
...viewer && { viewer }
|
|
12649
12719
|
};
|
|
12650
12720
|
return helperToolsModel(model, {
|
|
12651
12721
|
storage,
|
|
@@ -12856,6 +12926,7 @@ export {
|
|
|
12856
12926
|
ChatClosedError,
|
|
12857
12927
|
isScreenPlaceInput,
|
|
12858
12928
|
isTabId,
|
|
12929
|
+
AgentViewerError,
|
|
12859
12930
|
runHelper,
|
|
12860
12931
|
MAX_SERVER_TURNS_IN_ROW,
|
|
12861
12932
|
createChatEvents,
|
|
@@ -12928,4 +12999,4 @@ export {
|
|
|
12928
12999
|
InvalidWidgetAnswerError,
|
|
12929
13000
|
createChatService
|
|
12930
13001
|
};
|
|
12931
|
-
//# sourceMappingURL=chunk-
|
|
13002
|
+
//# sourceMappingURL=chunk-7M7M7DAN.js.map
|