@ykurilov/agent-chat-react 0.67.0 → 0.69.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 +10 -0
- package/README.md +4 -0
- package/dist/{chunk-JLGBVDAR.js → chunk-Z7X5D4OF.js} +114 -26
- package/dist/chunk-Z7X5D4OF.js.map +1 -0
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/panel.js +1 -1
- package/dist/types/chat-types.d.ts +2 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/labels.d.ts +4 -0
- package/dist/types/skin-contract.d.ts +25 -1
- package/dist/types/work-view/step-icons.d.ts +16 -0
- package/dist/types/work-view/step-phrases.d.ts +6 -1
- package/dist/types/work-view/work-layout.d.ts +23 -2
- package/dist/types/work-view/work-steps-part.d.ts +1 -1
- package/package.json +1 -1
- package/dist/chunk-JLGBVDAR.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @ykurilov/agent-chat-react
|
|
2
2
|
|
|
3
|
+
## 0.69.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- e6c03dc: Значки шагов и заголовки раздумий (106): в простом виде — ряд значков у «Сделано N шагов» и список «значок + фраза» (`StepIcon`, `icon` в `stepPhrases`, `guessStepIcon`); `thoughtTitles` у службы чата — заголовок раздумья от провайдера или пересказ дешёвой моделью в фоне, хранится в части раздумья, в запрос основной модели не идёт, расход `thought_title`; договор скина 28 (`WorkStepsView.live.icon`, `done.items`, `icons`, `moreIcons`, `Reasoning.title`); фраза навыка с именем.
|
|
8
|
+
|
|
9
|
+
## 0.68.0
|
|
10
|
+
|
|
11
|
+
No changes in this release.
|
|
12
|
+
|
|
3
13
|
## 0.67.0
|
|
4
14
|
|
|
5
15
|
No changes in this release.
|
package/README.md
CHANGED
|
@@ -66,6 +66,10 @@ import { AgentChat, ChatLabelsProvider, russianLabels } from "@ykurilov/agent-ch
|
|
|
66
66
|
поправку. Скину — `ChatSkin.steering`, `Composer.canSteer` и `UserMessage.pending` (договор v21, [docs/skin-v21.md](../../docs/skin-v21.md)).
|
|
67
67
|
- `liveDemos` — живые демонстрации: блок ` ```html-demo ` в ответе запускается в изолированной рамке во всю ширину ответа (на сервере —
|
|
68
68
|
`agent.liveDemos: true`). Скину — `AgentText.renderDemo` и `ChatSkin.demoColors` (договор v22, [docs/live-demos.md](../../docs/live-demos.md)).
|
|
69
|
+
- Значки шагов и заголовки раздумий (с 0.69, договор скина v28, [docs/skin-v28.md](../../docs/skin-v28.md)): в простом виде
|
|
70
|
+
ряд значков у «Сделано N шагов» и список «значок + фраза»; значок своему инструменту — `icon` рядом с фразами
|
|
71
|
+
`stepPhrases` (`StepIcon`), без него — `guessStepIcon` по имени. Заголовки раздумий приходят с сервера
|
|
72
|
+
(`thoughtTitles`) и показываются сами — в простом и подробном виде ([docs/work-view.md](../../docs/work-view.md)).
|
|
69
73
|
- Английский интерфейс: `<ChatLabelsProvider labels={englishLabels}>` — полный словарь (см. docs/getting-started.md, «Надписи»).
|
|
70
74
|
- `onTurnFinished({ chatId, messageId, status })` — ход закончен на экране: один раз на ход, когда ответ получил итог, включая остановку
|
|
71
75
|
и ошибку. Ответ, закрытый ради поправки на лету, получает своё событие перед ответом на поправку. Открытие чата с готовой историей события не даёт. На сервере то же — `onTurnFinished` у `createChatHandler`.
|
|
@@ -296,6 +296,8 @@ var russianWorkView = {
|
|
|
296
296
|
stepUnfinishedUnknown: "\u0428\u0430\u0433 \u043D\u0435 \u0437\u0430\u043A\u043E\u043D\u0447\u0435\u043D",
|
|
297
297
|
stepRepeated: (phrase, count) => `${phrase} \xD7${count}`,
|
|
298
298
|
thinking: "\u0414\u0443\u043C\u0430\u044E",
|
|
299
|
+
thought: (durationMs) => durationMs === null ? "\u041F\u043E\u0434\u0443\u043C\u0430\u043B" : `\u0414\u0443\u043C\u0430\u043B ${Math.max(1, Math.round(durationMs / 1e3))} \u0441\u0435\u043A`,
|
|
300
|
+
moreSteps: (count) => `+${count}`,
|
|
299
301
|
live: withEllipsis,
|
|
300
302
|
stepsDone: (count) => `${russianPlural.select(count) === "one" ? "\u0421\u0434\u0435\u043B\u0430\u043D" : "\u0421\u0434\u0435\u043B\u0430\u043D\u043E"} ${russianCount(count, { one: "\u0448\u0430\u0433", few: "\u0448\u0430\u0433\u0430", many: "\u0448\u0430\u0433\u043E\u0432" })}`,
|
|
301
303
|
helperRunning: (name) => `\u041F\u043E\u043C\u043E\u0449\u043D\u0438\u043A \xAB${name}\xBB \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442`,
|
|
@@ -310,6 +312,8 @@ var englishWorkViewLabels = {
|
|
|
310
312
|
stepUnfinishedUnknown: "A step wasn\u2019t finished",
|
|
311
313
|
stepRepeated: (phrase, count) => `${phrase} \xD7${count}`,
|
|
312
314
|
thinking: "Thinking",
|
|
315
|
+
thought: (durationMs) => durationMs === null ? "Thought" : `Thought for ${Math.max(1, Math.round(durationMs / 1e3))} s`,
|
|
316
|
+
moreSteps: (count) => `+${count}`,
|
|
313
317
|
live: withEllipsis,
|
|
314
318
|
stepsDone: (count) => `${count} ${count === 1 ? "step" : "steps"} done`,
|
|
315
319
|
helperRunning: (name) => `Helper \u201C${name}\u201D is working`,
|
|
@@ -4004,6 +4008,54 @@ function useThinkingStatus(active = true) {
|
|
|
4004
4008
|
};
|
|
4005
4009
|
}
|
|
4006
4010
|
|
|
4011
|
+
// src/work-view/step-icons.ts
|
|
4012
|
+
var SDK_TOOL_ICONS = {
|
|
4013
|
+
use_skill: "skill",
|
|
4014
|
+
web_search: "web",
|
|
4015
|
+
read_page: "web",
|
|
4016
|
+
page_screenshot: "snapshot",
|
|
4017
|
+
manage_memory: "memory",
|
|
4018
|
+
search_earlier_conversation: "search",
|
|
4019
|
+
check_tasks: "task",
|
|
4020
|
+
cancel_task: "task",
|
|
4021
|
+
generate_images: "image",
|
|
4022
|
+
show_image: "image",
|
|
4023
|
+
show_video: "video"
|
|
4024
|
+
};
|
|
4025
|
+
var WORD_ICONS = [
|
|
4026
|
+
["snapshot", ["screenshot", "snapshot", "capture"]],
|
|
4027
|
+
["image", ["image", "images", "picture", "photo", "draw"]],
|
|
4028
|
+
["video", ["video"]],
|
|
4029
|
+
["check", ["test", "tests", "check", "verify", "lint", "validate", "typecheck", "review"]],
|
|
4030
|
+
["edit", ["edit", "write", "patch", "replace", "update", "create", "save", "apply", "delete", "remove", "rename", "move", "insert"]],
|
|
4031
|
+
["search", ["search", "find", "grep", "lookup", "query"]],
|
|
4032
|
+
["read", ["read", "open", "view", "look", "get", "load", "list", "cat", "show", "inspect"]],
|
|
4033
|
+
["web", ["web", "browse", "browser", "url", "http", "page", "fetch"]],
|
|
4034
|
+
["run", ["run", "exec", "execute", "bash", "shell", "command", "terminal", "build", "install", "deploy"]],
|
|
4035
|
+
["skill", ["skill", "skills"]],
|
|
4036
|
+
["memory", ["memory", "remember", "note", "notes"]]
|
|
4037
|
+
];
|
|
4038
|
+
var wordsOf = (toolName) => toolName.replace(/([a-z0-9])([A-Z])/g, "$1 $2").toLowerCase().split(/[^a-z0-9]+/).filter(Boolean);
|
|
4039
|
+
function guessStepIcon(toolName) {
|
|
4040
|
+
const known = SDK_TOOL_ICONS[toolName];
|
|
4041
|
+
if (known) return known;
|
|
4042
|
+
if (toolName.startsWith("helper_")) return "helper";
|
|
4043
|
+
if (toolName.includes("__")) return "mcp";
|
|
4044
|
+
const words = wordsOf(toolName);
|
|
4045
|
+
return WORD_ICONS.find(([, keys]) => words.some((word) => keys.includes(word)))?.[0] ?? "tool";
|
|
4046
|
+
}
|
|
4047
|
+
var iconOfText = (value) => typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
4048
|
+
function stepIconOf(call, { phrases, fallback } = {}) {
|
|
4049
|
+
const entry = phrases && Object.hasOwn(phrases, call.toolName) ? phrases[call.toolName] : void 0;
|
|
4050
|
+
let own;
|
|
4051
|
+
try {
|
|
4052
|
+
own = typeof entry === "function" ? entry(call)?.icon : entry?.icon;
|
|
4053
|
+
} catch {
|
|
4054
|
+
own = void 0;
|
|
4055
|
+
}
|
|
4056
|
+
return iconOfText(own) ?? iconOfText(fallback?.icon) ?? guessStepIcon(call.toolName);
|
|
4057
|
+
}
|
|
4058
|
+
|
|
4007
4059
|
// src/agent-chat.tsx
|
|
4008
4060
|
import { getToolName as getToolName5, isToolUIPart as isToolUIPart3 } from "ai";
|
|
4009
4061
|
import { Fragment, memo as memo4, useCallback as useCallback17, useEffect as useEffect14, useId as useId2, useMemo as useMemo16, useRef as useRef17, useState as useState18 } from "react";
|
|
@@ -5706,7 +5758,8 @@ function stepPhraseOf(call, {
|
|
|
5706
5758
|
}
|
|
5707
5759
|
|
|
5708
5760
|
// src/work-view/work-layout.ts
|
|
5709
|
-
|
|
5761
|
+
var STEP_ICON_ROW_MAX = 8;
|
|
5762
|
+
function workLayoutOf(entries, { streaming, phrases, labels, thoughts = false }) {
|
|
5710
5763
|
const lastShown = entries.findLastIndex((entry) => entry.kind === "shown" && !entry.blank);
|
|
5711
5764
|
const layout = [];
|
|
5712
5765
|
let index = 0;
|
|
@@ -5729,39 +5782,56 @@ function workLayoutOf(entries, { streaming, phrases, labels }) {
|
|
|
5729
5782
|
} else if (next.blank) blanks.push({ kind: "shown", node: next.node });
|
|
5730
5783
|
else break;
|
|
5731
5784
|
}
|
|
5732
|
-
if (streaming && lastStep > lastShown)
|
|
5733
|
-
|
|
5734
|
-
|
|
5785
|
+
if (streaming && lastStep > lastShown) {
|
|
5786
|
+
const live = liveStepOf(group, phrases, labels);
|
|
5787
|
+
layout.push({ kind: "live", key, phrase: labels.live(live.phrase), icon: live.icon });
|
|
5788
|
+
} else {
|
|
5789
|
+
const done = doneLinesOf(thoughts ? group : group.filter((step) => step.kind === "tool"), phrases, labels, !streaming);
|
|
5735
5790
|
if (done.count > 0) layout.push({ kind: "done", key, ...done });
|
|
5736
5791
|
}
|
|
5737
5792
|
layout.push(...blanks);
|
|
5738
5793
|
}
|
|
5739
5794
|
return layout;
|
|
5740
5795
|
}
|
|
5741
|
-
function
|
|
5796
|
+
function liveStepOf(group, phrases, labels) {
|
|
5742
5797
|
const last = group.at(-1);
|
|
5743
5798
|
const running = group.findLast((step) => step.kind === "tool" && step.call.state === "running");
|
|
5744
|
-
if (last.kind === "tool" && running?.kind === "tool") return phraseOf(running, phrases, labels);
|
|
5745
|
-
|
|
5799
|
+
if (last.kind === "tool" && running?.kind === "tool") return { phrase: phraseOf(running, phrases, labels), icon: iconOf(running, phrases) };
|
|
5800
|
+
if (last.kind === "thinking") return { phrase: last.title ?? labels.thinking, icon: "thinking" };
|
|
5801
|
+
return { phrase: labels.stepRunning, icon: iconOf(last, phrases) };
|
|
5802
|
+
}
|
|
5803
|
+
function iconOf(step, phrases) {
|
|
5804
|
+
return stepIconOf(step.call, { phrases, fallback: step.fallback });
|
|
5746
5805
|
}
|
|
5747
5806
|
function phraseOf(step, phrases, labels, unfinished = false) {
|
|
5748
5807
|
return stepPhraseOf({ ...step.call, ...step.title !== void 0 && { title: step.title } }, { phrases, labels, fallback: step.fallback, unfinished });
|
|
5749
5808
|
}
|
|
5750
5809
|
function doneLinesOf(group, phrases, labels, finished2) {
|
|
5751
|
-
const
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5810
|
+
const all = group.map(
|
|
5811
|
+
(step) => step.kind === "tool" ? { ...toolLineOf(step, phrases, labels, finished2), tool: true } : { icon: "thinking", phrase: step.title ?? labels.thought(step.durationMs ?? null), failed: false, tool: false }
|
|
5812
|
+
);
|
|
5813
|
+
const calls = all.filter((line) => line.tool);
|
|
5814
|
+
const icons = all.map((line) => line.icon);
|
|
5815
|
+
return {
|
|
5816
|
+
steps: collapsed(calls, labels).map(({ phrase, failed }) => ({ phrase, failed })),
|
|
5817
|
+
count: calls.length,
|
|
5818
|
+
items: collapsed(all, labels),
|
|
5819
|
+
icons: icons.slice(0, STEP_ICON_ROW_MAX),
|
|
5820
|
+
moreIcons: Math.max(0, icons.length - STEP_ICON_ROW_MAX)
|
|
5821
|
+
};
|
|
5822
|
+
}
|
|
5823
|
+
function collapsed(lines, labels) {
|
|
5824
|
+
const runs = [];
|
|
5825
|
+
for (const line of lines) {
|
|
5826
|
+
const previous = runs.at(-1);
|
|
5827
|
+
if (previous?.phrase === line.phrase && previous.failed === line.failed && previous.icon === line.icon) previous.repeats++;
|
|
5828
|
+
else runs.push({ icon: line.icon, phrase: line.phrase, failed: line.failed, repeats: 1 });
|
|
5762
5829
|
}
|
|
5763
|
-
|
|
5764
|
-
|
|
5830
|
+
return runs.map(({ repeats, ...line }) => repeats > 1 ? { ...line, phrase: labels.stepRepeated(line.phrase, repeats) } : line);
|
|
5831
|
+
}
|
|
5832
|
+
function toolLineOf(step, phrases, labels, finished2) {
|
|
5833
|
+
const unfinished = finished2 && step.call.state === "running";
|
|
5834
|
+
return { icon: iconOf(step, phrases), phrase: phraseOf(step, phrases, labels, unfinished), failed: step.call.state === "error" || unfinished };
|
|
5765
5835
|
}
|
|
5766
5836
|
|
|
5767
5837
|
// src/work-view/work-steps-part.tsx
|
|
@@ -5776,7 +5846,19 @@ function WorkStepsPart({
|
|
|
5776
5846
|
const labels = useChatLabels();
|
|
5777
5847
|
const [open, setOpen] = usePartOpen(expanded, `${item.key}:work`);
|
|
5778
5848
|
if (skin.WorkSteps) {
|
|
5779
|
-
return item.kind === "live" ? /* @__PURE__ */ jsx8(skin.WorkSteps, { state: "live", phrase: item.phrase }) : /* @__PURE__ */ jsx8(
|
|
5849
|
+
return item.kind === "live" ? /* @__PURE__ */ jsx8(skin.WorkSteps, { state: "live", phrase: item.phrase, icon: item.icon }) : /* @__PURE__ */ jsx8(
|
|
5850
|
+
skin.WorkSteps,
|
|
5851
|
+
{
|
|
5852
|
+
state: "done",
|
|
5853
|
+
steps: item.steps,
|
|
5854
|
+
count: item.count,
|
|
5855
|
+
items: item.items,
|
|
5856
|
+
icons: item.icons,
|
|
5857
|
+
moreIcons: item.moreIcons,
|
|
5858
|
+
open,
|
|
5859
|
+
onOpenChange: setOpen
|
|
5860
|
+
}
|
|
5861
|
+
);
|
|
5780
5862
|
}
|
|
5781
5863
|
if (item.kind === "live") return /* @__PURE__ */ jsx8(skin.ToolCallRow, { toolName: item.phrase, title: item.phrase, state: "running", open: false, onOpenChange: keepClosed });
|
|
5782
5864
|
const title = labels.workView.stepsDone(item.count);
|
|
@@ -6394,6 +6476,7 @@ var AgentAnswer = memo4(function AgentAnswer2({
|
|
|
6394
6476
|
}) {
|
|
6395
6477
|
const labels = useChatLabels();
|
|
6396
6478
|
const durations = message.metadata?.reasoningDurationsMs ?? {};
|
|
6479
|
+
const thoughtTitles = message.metadata?.thoughtTitles ?? {};
|
|
6397
6480
|
let reasoningIndex = 0;
|
|
6398
6481
|
const simple = extensions.workView === "simple";
|
|
6399
6482
|
const entries = [];
|
|
@@ -6415,10 +6498,12 @@ var AgentAnswer = memo4(function AgentAnswer2({
|
|
|
6415
6498
|
if (part.type === "reasoning") {
|
|
6416
6499
|
const ordinal = String(reasoningIndex++);
|
|
6417
6500
|
const streaming = part.state === "streaming";
|
|
6418
|
-
|
|
6501
|
+
const durationMs = streaming ? null : durations[ordinal] ?? null;
|
|
6502
|
+
const title = streaming ? void 0 : thoughtTitles[ordinal];
|
|
6503
|
+
if (!streaming && part.text.trim().length === 0 && (title === void 0 || !simple)) return;
|
|
6419
6504
|
step(
|
|
6420
6505
|
index,
|
|
6421
|
-
{ kind: "thinking" },
|
|
6506
|
+
{ kind: "thinking", durationMs, ...title !== void 0 && { title } },
|
|
6422
6507
|
/* @__PURE__ */ jsx9(
|
|
6423
6508
|
ExpandablePart,
|
|
6424
6509
|
{
|
|
@@ -6427,7 +6512,8 @@ var AgentAnswer = memo4(function AgentAnswer2({
|
|
|
6427
6512
|
partId: partKey(message.id, index),
|
|
6428
6513
|
text: part.text,
|
|
6429
6514
|
streaming,
|
|
6430
|
-
durationMs
|
|
6515
|
+
durationMs,
|
|
6516
|
+
...title !== void 0 && { title }
|
|
6431
6517
|
},
|
|
6432
6518
|
key
|
|
6433
6519
|
)
|
|
@@ -6535,7 +6621,7 @@ var AgentAnswer = memo4(function AgentAnswer2({
|
|
|
6535
6621
|
else step(index, toolStepOf(part), row);
|
|
6536
6622
|
}
|
|
6537
6623
|
});
|
|
6538
|
-
const parts = simple ? workLayoutOf(entries, { streaming: status === "streaming", phrases: extensions.stepPhrases, labels: labels.workView }).map(
|
|
6624
|
+
const parts = simple ? workLayoutOf(entries, { streaming: status === "streaming", phrases: extensions.stepPhrases, labels: labels.workView, thoughts: Object.keys(thoughtTitles).length > 0 }).map(
|
|
6539
6625
|
(item) => item.kind === "shown" ? item.node : /* @__PURE__ */ jsx9(WorkStepsPart, { skin, expanded, item }, `${item.key}:work`)
|
|
6540
6626
|
) : entries.map((entry) => entry.kind === "shown" ? entry.node : null);
|
|
6541
6627
|
const text = messageText(message, { voiceAnswer });
|
|
@@ -7078,10 +7164,12 @@ export {
|
|
|
7078
7164
|
useAgentChat,
|
|
7079
7165
|
useModelChoice,
|
|
7080
7166
|
useThinkingStatus,
|
|
7167
|
+
guessStepIcon,
|
|
7168
|
+
stepIconOf,
|
|
7081
7169
|
AgentChat,
|
|
7082
7170
|
useChatList,
|
|
7083
7171
|
useChatListView,
|
|
7084
7172
|
activeChatTitle,
|
|
7085
7173
|
useWorkspaceListSync
|
|
7086
7174
|
};
|
|
7087
|
-
//# sourceMappingURL=chunk-
|
|
7175
|
+
//# sourceMappingURL=chunk-Z7X5D4OF.js.map
|