@ykurilov/agent-chat-react 0.0.0-stage → 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 +1688 -0
- package/LICENSE +21 -0
- package/README.md +132 -2
- package/dist/chunk-7DVTSVKQ.js +6967 -0
- package/dist/chunk-7DVTSVKQ.js.map +1 -0
- package/dist/index.js +501 -0
- package/dist/index.js.map +1 -0
- package/dist/panel.js +399 -0
- package/dist/panel.js.map +1 -0
- package/dist/types/agent-chat-extensions.d.ts +80 -0
- package/dist/types/agent-chat.d.ts +103 -0
- package/dist/types/agent-panel/agent-panel-hooks.d.ts +14 -0
- package/dist/types/agent-panel/agent-panel-provider.d.ts +24 -0
- package/dist/types/agent-panel/agent-panel-skin.d.ts +41 -0
- package/dist/types/agent-panel/agent-panel.d.ts +13 -0
- package/dist/types/agent-panel/index.d.ts +8 -0
- package/dist/types/agent-panel/panel-context.d.ts +46 -0
- package/dist/types/agent-panel/panel-state.d.ts +12 -0
- package/dist/types/answer-editing/answer-editing.d.ts +25 -0
- package/dist/types/app-bridge/app-bridge.d.ts +50 -0
- package/dist/types/app-bridge/browser-calls.d.ts +24 -0
- package/dist/types/app-bridge/create-app-bridge.d.ts +35 -0
- package/dist/types/app-bridge/remembered-ids.d.ts +6 -0
- package/dist/types/app-bridge/tab-id.d.ts +10 -0
- package/dist/types/app-events.d.ts +39 -0
- package/dist/types/app-refusal.d.ts +21 -0
- package/dist/types/attachments-contract.d.ts +82 -0
- package/dist/types/background-tasks/use-background-tasks.d.ts +53 -0
- package/dist/types/chat-access.d.ts +33 -0
- package/dist/types/chat-list/active-chat-memory.d.ts +5 -0
- package/dist/types/chat-list/chat-list-client.d.ts +35 -0
- package/dist/types/chat-list/chat-list-skin.d.ts +63 -0
- package/dist/types/chat-list/chat-workspace.d.ts +17 -0
- package/dist/types/chat-list/use-chat-list-view.d.ts +12 -0
- package/dist/types/chat-list/use-chat-list.d.ts +47 -0
- package/dist/types/chat-list/use-workspace-list-sync.d.ts +7 -0
- package/dist/types/chat-state/chat-state.d.ts +27 -0
- package/dist/types/chat-types.d.ts +85 -0
- package/dist/types/chat-watch/chat-watch.d.ts +57 -0
- package/dist/types/close-stopped-tool-calls.d.ts +8 -0
- package/dist/types/composer-actions.d.ts +29 -0
- package/dist/types/diagrams/diagram-renders.d.ts +16 -0
- package/dist/types/diagrams/mermaid-blocks.d.ts +18 -0
- package/dist/types/diagrams/unique-svg-ids.d.ts +6 -0
- package/dist/types/diagrams/use-diagram-blocks.d.ts +25 -0
- package/dist/types/diagrams/use-diagram-colors.d.ts +8 -0
- package/dist/types/dictation-field.d.ts +19 -0
- package/dist/types/expanded-parts.d.ts +11 -0
- package/dist/types/feed-announcement.d.ts +7 -0
- package/dist/types/helpers/helper-call.d.ts +57 -0
- package/dist/types/index.d.ts +53 -0
- package/dist/types/labels.d.ts +468 -0
- package/dist/types/live-demos/answer-fences.d.ts +25 -0
- package/dist/types/live-demos/live-demo-document.d.ts +42 -0
- package/dist/types/live-demos/live-demo-frame.d.ts +14 -0
- package/dist/types/live-demos/use-live-demo-blocks.d.ts +18 -0
- package/dist/types/liveness/connection-errors.d.ts +15 -0
- package/dist/types/liveness/reconnect-attempts.d.ts +14 -0
- package/dist/types/liveness/request-deadline.d.ts +16 -0
- package/dist/types/liveness/silence-watchdog.d.ts +21 -0
- package/dist/types/media-viewer/answer-file-images.d.ts +18 -0
- package/dist/types/media-viewer/collect-viewer-items.d.ts +16 -0
- package/dist/types/media-viewer/generated-images.d.ts +20 -0
- package/dist/types/media-viewer/media-viewer-types.d.ts +17 -0
- package/dist/types/media-viewer/open-attachments.d.ts +9 -0
- package/dist/types/media-viewer/use-media-viewer.d.ts +23 -0
- package/dist/types/memory/agent-memory.d.ts +13 -0
- package/dist/types/memory/memory-client.d.ts +19 -0
- package/dist/types/memory/memory-skin.d.ts +103 -0
- package/dist/types/memory/memory-tree.d.ts +17 -0
- package/dist/types/memory/memory-types.d.ts +77 -0
- package/dist/types/memory/use-memory-notes.d.ts +23 -0
- package/dist/types/message-actions.d.ts +45 -0
- package/dist/types/message-feed.d.ts +27 -0
- package/dist/types/notices/agent-notices.d.ts +40 -0
- package/dist/types/pause.d.ts +2 -0
- package/dist/types/server-refusal.d.ts +16 -0
- package/dist/types/skin-contract.d.ts +687 -0
- package/dist/types/spending-status.d.ts +76 -0
- package/dist/types/steering/corrections.d.ts +19 -0
- package/dist/types/step-reset.d.ts +15 -0
- package/dist/types/subject-chat/subject-chat-loading.d.ts +8 -0
- package/dist/types/subject-chat/use-subject-chat-id.d.ts +21 -0
- package/dist/types/thinking-status/thinking-status.d.ts +33 -0
- package/dist/types/turn-finished.d.ts +14 -0
- package/dist/types/use-agent-chat.d.ts +228 -0
- package/dist/types/use-model-choice.d.ts +31 -0
- package/dist/types/use-voice-dialog.d.ts +18 -0
- package/dist/types/use-voice-dictation.d.ts +17 -0
- package/dist/types/voice-dialog.d.ts +103 -0
- package/dist/types/voice-input.d.ts +47 -0
- package/dist/types/voice-tags.d.ts +18 -0
- package/dist/types/voice-turn.d.ts +11 -0
- package/dist/types/widgets/custom-widget-guard.d.ts +21 -0
- package/dist/types/widgets/form-check.d.ts +29 -0
- package/dist/types/widgets/suggested-replies.d.ts +6 -0
- package/dist/types/widgets/use-widget-answer.d.ts +54 -0
- package/dist/types/widgets/widget-answer-keys.d.ts +14 -0
- package/dist/types/widgets/widget-messages.d.ts +14 -0
- package/dist/types/widgets/widget-part.d.ts +17 -0
- package/dist/types/widgets/widget-view.d.ts +50 -0
- package/dist/types/without-markdown.d.ts +1 -0
- package/dist/types/work-view/step-phrases.d.ts +37 -0
- package/dist/types/work-view/work-layout.d.ts +57 -0
- package/dist/types/work-view/work-steps-part.d.ts +15 -0
- package/package.json +53 -3
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** Что пошло не так с голосом, в терминах человека; готовые надписи живут в словаре чата. */
|
|
2
|
+
export type VoiceErrorKind = "permission_denied" | "no_microphone" | "unsupported" | "network" | "service_unavailable" | "rate_limited" | "time_limit"
|
|
3
|
+
/** Лимит расходов исчерпан. */
|
|
4
|
+
| "limit"
|
|
5
|
+
/** Нет доступа: не вошёл или приложение отказало. */
|
|
6
|
+
| "forbidden"
|
|
7
|
+
/** Запись слишком длинная. */
|
|
8
|
+
| "too_long" | "other";
|
|
9
|
+
/** Подробности ошибки для подписи. */
|
|
10
|
+
export interface VoiceErrorDetails {
|
|
11
|
+
/** У `time_limit`: предел записи в секундах, как его назвал сервер. */
|
|
12
|
+
maxSessionSeconds?: number;
|
|
13
|
+
}
|
|
14
|
+
/** О какой записи речь: чат, на который ляжет расход, и язык человека (`AgentChat` передаёт язык словаря). */
|
|
15
|
+
export interface VoiceStartContext {
|
|
16
|
+
chatId?: string;
|
|
17
|
+
language?: string;
|
|
18
|
+
}
|
|
19
|
+
/** Продиктованный текст целиком: подтверждённая часть и часть, которая ещё может измениться. */
|
|
20
|
+
export interface DictatedText {
|
|
21
|
+
finalText: string;
|
|
22
|
+
interimText: string;
|
|
23
|
+
}
|
|
24
|
+
/** Кто слушает диктовку. После `onError` всегда приходит `onEnd`. */
|
|
25
|
+
export interface VoiceListener {
|
|
26
|
+
/** Микрофон и соединение готовы, идёт запись. */
|
|
27
|
+
onConnected(): void;
|
|
28
|
+
/** Накопленный текст диктовки целиком. */
|
|
29
|
+
onText(text: DictatedText): void;
|
|
30
|
+
onError(kind: VoiceErrorKind, details?: VoiceErrorDetails): void;
|
|
31
|
+
/** Диктовка закончена, ресурсы освобождены. */
|
|
32
|
+
onEnd(): void;
|
|
33
|
+
/** Текст закреплён, сервер причёсывает его моделью (только режим `relay` с чисткой). Дальше `onPolished` или сразу `onEnd`. */
|
|
34
|
+
onPolishing?(): void;
|
|
35
|
+
/** Исправленный текст всей диктовки; приходит только если чистка удалась. Затем `onEnd`. */
|
|
36
|
+
onPolished?(text: string): void;
|
|
37
|
+
}
|
|
38
|
+
export interface VoiceSession {
|
|
39
|
+
/** Закончить запись, дождаться остатка речи; затем `onEnd`. */
|
|
40
|
+
stop(): void;
|
|
41
|
+
/** Бросить диктовку: слушателя больше не звать. */
|
|
42
|
+
cancel(): void;
|
|
43
|
+
}
|
|
44
|
+
/** Голосовой ввод для `AgentChat`; настоящий делает `createVoiceInput` из `@ykurilov/agent-chat-voice`. */
|
|
45
|
+
export interface VoiceInput {
|
|
46
|
+
start(listener: VoiceListener, context?: VoiceStartContext): VoiceSession;
|
|
47
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface VoiceTagOptions {
|
|
2
|
+
/** Недописанный тег в конце текста («[laug») тоже вырезается: так в потоке ответа тег не мелькает на экране. */
|
|
3
|
+
partialTail?: boolean;
|
|
4
|
+
}
|
|
5
|
+
/** Тег, найденный в тексте: `at` — место в тексте без тегов, где он стоял. */
|
|
6
|
+
export interface VoiceTagMatch {
|
|
7
|
+
at: number;
|
|
8
|
+
name: string;
|
|
9
|
+
}
|
|
10
|
+
export interface SplitVoiceTags {
|
|
11
|
+
/** Текст без тегов: рядом стоявший пробел убран, остальное не изменено. */
|
|
12
|
+
plain: string;
|
|
13
|
+
tags: VoiceTagMatch[];
|
|
14
|
+
}
|
|
15
|
+
/** Текст без тегов голоса и список вырезанных тегов с их местом. */
|
|
16
|
+
export declare function splitVoiceTags(text: string, options?: VoiceTagOptions): SplitVoiceTags;
|
|
17
|
+
/** Текст без тегов голоса. */
|
|
18
|
+
export declare function stripVoiceTags(text: string, options?: VoiceTagOptions): string;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AgentChatMessage } from "./chat-types.js";
|
|
2
|
+
/** Тип части-отметки: сообщение человека сказано голосом (то же, что `VOICE_MODE_PART_TYPE` в ядре). */
|
|
3
|
+
export declare const VOICE_MODE_PART_TYPE = "data-voice-mode";
|
|
4
|
+
export declare function isVoiceMessage(message: Pick<AgentChatMessage, "parts">): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Ответы голосовых ходов: сообщения агента, идущие за сообщением человека с отметкой голосового режима.
|
|
7
|
+
* Только в них теги голоса («[laughs]») слышны, но не видны; в остальных скобки — обычный текст.
|
|
8
|
+
*/
|
|
9
|
+
export declare function voiceAnswerIds(messages: readonly AgentChatMessage[]): Set<string>;
|
|
10
|
+
/** То же, что `voiceAnswerIds`, но пока состав не изменился — тот же объект: лента не перерисовывается на каждый кусок ответа. */
|
|
11
|
+
export declare function useVoiceAnswerIds(messages: readonly AgentChatMessage[]): ReadonlySet<string>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Component } from "react";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
/**
|
|
4
|
+
* Граница вокруг своего виджета страницы: упавший компонент (например, на негодном входе модели) не роняет ленту.
|
|
5
|
+
* После падения виджет показывается запасным видом скина.
|
|
6
|
+
*/
|
|
7
|
+
export declare class CustomWidgetGuard extends Component<{
|
|
8
|
+
onCrash: () => void;
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
}, {
|
|
11
|
+
crashed: boolean;
|
|
12
|
+
}> {
|
|
13
|
+
state: {
|
|
14
|
+
crashed: boolean;
|
|
15
|
+
};
|
|
16
|
+
static getDerivedStateFromError(): {
|
|
17
|
+
crashed: boolean;
|
|
18
|
+
};
|
|
19
|
+
componentDidCatch(): void;
|
|
20
|
+
render(): ReactNode;
|
|
21
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { WidgetLabels } from "../labels.js";
|
|
2
|
+
import type { FormFieldView } from "../skin-contract.js";
|
|
3
|
+
/** Самый длинный текст поля формы (data-model, «Ответы»). */
|
|
4
|
+
export declare const FORM_TEXT_MAX_LENGTH = 2000;
|
|
5
|
+
/** Тексты ошибок полей: из словаря надписей, чтобы проверку можно было звать вне React. */
|
|
6
|
+
export interface FormCheckMessages {
|
|
7
|
+
required: string;
|
|
8
|
+
notNumber: string;
|
|
9
|
+
notDate: string;
|
|
10
|
+
outOfRange: (min: string | undefined, max: string | undefined) => string;
|
|
11
|
+
tooLong: (max: number) => string;
|
|
12
|
+
}
|
|
13
|
+
export declare function formCheckMessages(labels: WidgetLabels): FormCheckMessages;
|
|
14
|
+
export type FormValues = Record<string, string | number>;
|
|
15
|
+
export type FormCheck = {
|
|
16
|
+
ok: true;
|
|
17
|
+
answer: FormValues;
|
|
18
|
+
} | {
|
|
19
|
+
ok: false;
|
|
20
|
+
errors: Record<string, string>;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Проверка формы до отправки (FR-014): обязательные поля, числа и даты в пределах, вариант из списка, текст до 2000
|
|
24
|
+
* знаков. Верное — ответ для сервера: числа числами, текст без пробелов по краям, пустые необязательные поля опущены,
|
|
25
|
+
* поля не из формы не уходят.
|
|
26
|
+
*/
|
|
27
|
+
export declare function checkForm(fields: readonly FormFieldView[], values: Readonly<Record<string, string | number | undefined>>, messages: FormCheckMessages): FormCheck;
|
|
28
|
+
/** Выбор нескольких вариантов: в пределах `min..max` и только из списка — выбор в порядке вариантов; иначе `null`. */
|
|
29
|
+
export declare function checkChoices(options: readonly string[], chosen: readonly string[], min: number, max: number): string[] | null;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AgentChatMessage } from "../chat-types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Подсказки ответа: последний вызов `suggest_replies` в последнем ответе ветки. Пока идёт ход или последнее слово
|
|
4
|
+
* за человеком — подсказок нет. Пустые строки и не строки отбрасываются.
|
|
5
|
+
*/
|
|
6
|
+
export declare function suggestedRepliesOf(messages: readonly AgentChatMessage[], busy: boolean): string[] | null;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { Dispatch, SetStateAction } from "react";
|
|
2
|
+
import type { AgentChatMessage } from "../chat-types.js";
|
|
3
|
+
import type { ServerRefusal } from "../server-refusal.js";
|
|
4
|
+
import type { SpendingInfo } from "../spending-status.js";
|
|
5
|
+
/**
|
|
6
|
+
* Почему ответ на виджет не принят: виджет снова активен, причина — словами у виджета. `refused` — приложение не пустило
|
|
7
|
+
* ход, `answer_refused` — приложение отказало в самом ответе (`checkAnswer`); слова — в `text`.
|
|
8
|
+
* `check_timeout` — проверка ответа не уложилась в срок: виджет открыт, текст — подпись `widgets.answerCheckTimeout`.
|
|
9
|
+
*/
|
|
10
|
+
export type WidgetFailureKind = "connection" | "spending_limit" | "busy" | "too_many_turns" | "already_answered" | "rejected" | "refused" | "answer_refused" | "check_timeout";
|
|
11
|
+
type ResumeOutcome = "streaming" | "nothing" | "failed";
|
|
12
|
+
export interface WidgetAnswerDeps {
|
|
13
|
+
chatUrl: string;
|
|
14
|
+
request: (input: string, init?: RequestInit) => Promise<Response>;
|
|
15
|
+
requestTimeoutMs: () => number;
|
|
16
|
+
/** Поля страницы, которые несёт каждый запрос хода (вкладка, место на экране, пояс). */
|
|
17
|
+
pageFields: () => Record<string, unknown>;
|
|
18
|
+
/** Жизнь чата: смена чата обрывает ожидание. */
|
|
19
|
+
chatSignal: () => AbortSignal;
|
|
20
|
+
setMessages: Dispatch<SetStateAction<AgentChatMessage[]>>;
|
|
21
|
+
setResuming: (resuming: boolean) => void;
|
|
22
|
+
resumeWithProbe: (signal: AbortSignal) => Promise<ResumeOutcome>;
|
|
23
|
+
/** Перечитывает историю; сорвавшееся чтение повторяется серией попыток. */
|
|
24
|
+
rereadHistory: (signal: AbortSignal) => Promise<void>;
|
|
25
|
+
/** Новые события ответа с вызовом `toolCallId` придут живыми с перечитанной историей (`AppEventReport.expectLive`). */
|
|
26
|
+
expectLiveEventsOf: (toolCallId: string) => void;
|
|
27
|
+
startSeries: () => void;
|
|
28
|
+
/** Приложение отказало ходу: сообщает странице (`onTurnRefused`). */
|
|
29
|
+
announceAppRefusal: (refusal: ServerRefusal | null) => void;
|
|
30
|
+
/** Отказ 429: лимит расходов (поле ввода блокируется, как при отказе на отправку) или место хода. */
|
|
31
|
+
spendingRefusalOf: (response: Response) => Promise<SpendingInfo | null>;
|
|
32
|
+
showSpendingExhausted: (info: SpendingInfo) => void;
|
|
33
|
+
errorKindOf: (response: Response) => Promise<string | undefined>;
|
|
34
|
+
}
|
|
35
|
+
export interface WidgetAnswerState {
|
|
36
|
+
/** Ответ человека на виджет. `true` — сервер принял; `onAccepted` зовётся сразу, как принял, до продолжения хода. */
|
|
37
|
+
answerWidget: (toolCallId: string, answer: unknown, onAccepted?: () => void) => Promise<boolean>;
|
|
38
|
+
/** Виджет, ответ на который сейчас идёт на сервер. */
|
|
39
|
+
widgetPendingId: string | null;
|
|
40
|
+
widgetFailure: {
|
|
41
|
+
id: string;
|
|
42
|
+
kind: WidgetFailureKind;
|
|
43
|
+
text?: string;
|
|
44
|
+
} | null;
|
|
45
|
+
/** Ответ на виджет в пути или его продолжение ещё подключается: ход, который начнёт сервер, — свой. */
|
|
46
|
+
answeringWidget: () => boolean;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Ответ на виджет (contracts/core-and-http.md, «Маршрут ответа»): `POST {api}/:chatId/widgets/:toolCallId`, тело
|
|
50
|
+
* `{ answer }`. Принятый ответ продолжает ход так же, как решение по подтверждению: лента подключается к продолжению,
|
|
51
|
+
* и оно дописывает то же сообщение.
|
|
52
|
+
*/
|
|
53
|
+
export declare function useWidgetAnswer(deps: WidgetAnswerDeps): WidgetAnswerState;
|
|
54
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** «выбрано» — ответ `ask_choice` и `ask_multi_choice`. */
|
|
2
|
+
export declare const CHOSEN_KEY = "\u0432\u044B\u0431\u0440\u0430\u043D\u043E";
|
|
3
|
+
/** «оценка» — ответ `ask_rating`. */
|
|
4
|
+
export declare const RATING_KEY = "\u043E\u0446\u0435\u043D\u043A\u0430";
|
|
5
|
+
/** «поля» — ответ `ask_form`. */
|
|
6
|
+
export declare const FIELDS_KEY = "\u043F\u043E\u043B\u044F";
|
|
7
|
+
/** «ответ» — ключ пометки «закрыт сообщением». */
|
|
8
|
+
export declare const BY_MESSAGE_KEY = "\u043E\u0442\u0432\u0435\u0442";
|
|
9
|
+
/** «сообщением» — значение пометки «закрыт сообщением»: `{ "ответ": "сообщением" }`. */
|
|
10
|
+
export declare const BY_MESSAGE_VALUE = "\u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435\u043C";
|
|
11
|
+
/** «Задавай один вопрос за раз» — ошибка лишнего ждущего вызова в шаге: такой виджет не показывается. */
|
|
12
|
+
export declare const ONE_QUESTION_AT_A_TIME = "\u0417\u0430\u0434\u0430\u0432\u0430\u0439 \u043E\u0434\u0438\u043D \u0432\u043E\u043F\u0440\u043E\u0441 \u0437\u0430 \u0440\u0430\u0437";
|
|
13
|
+
/** Результат вызова — пометка «человек ответил сообщением, а не виджетом». */
|
|
14
|
+
export declare function isAnsweredByMessage(output: unknown): boolean;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AgentChatMessage } from "../chat-types.js";
|
|
2
|
+
/** Ответ лежит в вызове; `resumed` — ход продолжается, сообщение дописывается потоком. */
|
|
3
|
+
export declare function withWidgetAnswer(messages: AgentChatMessage[], toolCallId: string, answer: unknown, resumed: boolean): AgentChatMessage[];
|
|
4
|
+
/** Ход кончился: отвеченные вызовы, помеченные «в пути», получают свой результат. */
|
|
5
|
+
export declare function withWidgetAnswersSettled(messages: AgentChatMessage[]): AgentChatMessage[];
|
|
6
|
+
/**
|
|
7
|
+
* История идущего хода сразу после ответа на виджет: последний ответ «идёт», а его последняя часть — отвеченный вызов.
|
|
8
|
+
* Вызов помечается «в пути», чтобы продолжение дописало то же сообщение.
|
|
9
|
+
*/
|
|
10
|
+
export declare function withWidgetContinuationMarked(messages: AgentChatMessage[]): AgentChatMessage[];
|
|
11
|
+
/** Ждущие виджеты последнего ответа закрыты сообщением человека (сервер делает то же, FR-006). */
|
|
12
|
+
export declare function withPendingWidgetsClosed(messages: AgentChatMessage[]): AgentChatMessage[];
|
|
13
|
+
/** В последнем ответе ждёт запрос подтверждения: его решает только кнопка, слова голосом его не закрывают. */
|
|
14
|
+
export declare function hasPendingApproval(messages: readonly AgentChatMessage[]): boolean;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ComponentType } from "react";
|
|
2
|
+
import type { CustomWidgetProps, WidgetView } from "../skin-contract.js";
|
|
3
|
+
import type { WidgetCall } from "./widget-view.js";
|
|
4
|
+
/**
|
|
5
|
+
* Виджет в ленте: вид для скина и свой компонент страницы внутри него. Ошибки полей формы живут здесь, пока человек
|
|
6
|
+
* не отправит форму верно. Упавший свой компонент заменяется запасным видом скина.
|
|
7
|
+
*/
|
|
8
|
+
export declare const WidgetPart: import("react").MemoExoticComponent<({ Widget, Custom, call, chatId, pending, failure, onAnswer, }: {
|
|
9
|
+
Widget: ComponentType<WidgetView>;
|
|
10
|
+
/** Компонент своего виджета из `widgets[name]`; нет — запасной вид скина. */
|
|
11
|
+
Custom?: ComponentType<CustomWidgetProps<unknown, unknown>>;
|
|
12
|
+
call: WidgetCall;
|
|
13
|
+
chatId: string;
|
|
14
|
+
pending: boolean;
|
|
15
|
+
failure?: string;
|
|
16
|
+
onAnswer: (toolCallId: string, answer: unknown) => void;
|
|
17
|
+
}) => import("react").JSX.Element | null>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { DynamicToolUIPart, ToolUIPart } from "ai";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
import type { CustomWidgetProps, WidgetView } from "../skin-contract.js";
|
|
4
|
+
import type { FormCheckMessages } from "./form-check.js";
|
|
5
|
+
import { BY_MESSAGE_KEY } from "./widget-answer-keys.js";
|
|
6
|
+
/** Подсказки: не ждут, рисуются кнопками под ответом (suggested-replies.ts), в ленте их вызова не видно. */
|
|
7
|
+
export declare const SUGGEST_REPLIES = "suggest_replies";
|
|
8
|
+
type ToolPart = ToolUIPart | DynamicToolUIPart;
|
|
9
|
+
/** Вызов виджета в ленте: что спросили, ждёт ли он и чем ответили. */
|
|
10
|
+
export interface WidgetCall {
|
|
11
|
+
toolCallId: string;
|
|
12
|
+
name: string;
|
|
13
|
+
input: unknown;
|
|
14
|
+
/** `closed` — «Стоп», сбой или ответ, который уже не ждёт (FR-007). */
|
|
15
|
+
state: CustomWidgetProps["state"];
|
|
16
|
+
/** Ответ из результата вызова, у отвеченного. */
|
|
17
|
+
answer?: unknown;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Часть вызова → виджет. `null` — не виджет (обычная строка инструмента), `"hidden"` — виджет не показывается:
|
|
21
|
+
* модель ещё пишет вход, вход негодный или это лишний вопрос шага («Задавай один вопрос за раз»).
|
|
22
|
+
* `awaitingHere` — часть стоит в последнем ответе текущей ветки, и этот ответ ждёт человека: только тогда виджет активен.
|
|
23
|
+
* Вызов без результата и без подтверждения в ждущем ответе — тоже виджет: свой, которого страница не знает (FR-018).
|
|
24
|
+
*/
|
|
25
|
+
export declare function widgetCallOf(part: ToolPart, where: {
|
|
26
|
+
awaitingHere: boolean;
|
|
27
|
+
customNames: ReadonlySet<string>;
|
|
28
|
+
}): WidgetCall | "hidden" | null;
|
|
29
|
+
/** Что даёт слой поведения виду виджета. */
|
|
30
|
+
export interface WidgetControls {
|
|
31
|
+
/** Ответ уходит на сервер. */
|
|
32
|
+
pending: boolean;
|
|
33
|
+
failure?: string;
|
|
34
|
+
/** Есть только у активного виджета. */
|
|
35
|
+
onAnswer?: (answer: unknown) => void;
|
|
36
|
+
/** Ошибки полей формы после неудачной проверки. */
|
|
37
|
+
fieldErrors?: Readonly<Record<string, string>>;
|
|
38
|
+
/** Проверка формы не прошла (или прошла — тогда ошибок нет): ошибки показать у полей. */
|
|
39
|
+
onInvalid?: (errors: Record<string, string>) => void;
|
|
40
|
+
messages: FormCheckMessages;
|
|
41
|
+
/** Компонент своего виджета со страницы. */
|
|
42
|
+
content?: ReactNode;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Виджет → вид для скина (договор v13). Ответ уходит в форме результата вызова (data-model, «Ответы»):
|
|
46
|
+
* `{ "выбрано": … }`, `{ "оценка": … }`, `{ "поля": … }`. Негодный вход базового виджета — `null`.
|
|
47
|
+
*/
|
|
48
|
+
export declare function widgetViewOf(call: WidgetCall, controls: WidgetControls): WidgetView | null;
|
|
49
|
+
/** Ключ пометки «закрыт сообщением» — для оптимистичной отметки в ленте, когда человек написал вместо ответа. */
|
|
50
|
+
export { BY_MESSAGE_KEY };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function withoutMarkdown(markdown: string): string;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { WorkViewLabels } from "../labels.js";
|
|
2
|
+
import type { ToolCallState } from "../skin-contract.js";
|
|
3
|
+
/**
|
|
4
|
+
* Вид работы агента в ленте. `detailed` — мысли и строки инструментов с входом и выходом, как до 0.45.
|
|
5
|
+
* `simple` — пока ход идёт, одна живая строка с текущим шагом; после хода шаги свёрнуты в «Сделано N шагов».
|
|
6
|
+
*/
|
|
7
|
+
export type WorkView = "detailed" | "simple";
|
|
8
|
+
/** Вызов инструмента для фразы. Вход и выход бывают не всегда: вход ещё пишется или скрыт правами. */
|
|
9
|
+
export interface StepCall {
|
|
10
|
+
toolName: string;
|
|
11
|
+
state: ToolCallState;
|
|
12
|
+
input?: unknown;
|
|
13
|
+
output?: unknown;
|
|
14
|
+
}
|
|
15
|
+
/** Фразы шага: пока идёт («Делаю календарь»), готово («Сделал календарь»), не вышло (необязательно). */
|
|
16
|
+
export interface StepPhraseText {
|
|
17
|
+
running: string;
|
|
18
|
+
done: string;
|
|
19
|
+
failed?: string;
|
|
20
|
+
}
|
|
21
|
+
/** Фразы шага готовые или по вызову. Нет ответа (`undefined`) — общая фраза. */
|
|
22
|
+
export type StepPhrase = StepPhraseText | ((call: StepCall) => Partial<StepPhraseText> | undefined);
|
|
23
|
+
/** Фразы шагов приложения: имя инструмента → фразы. */
|
|
24
|
+
export type StepPhrases = Record<string, StepPhrase>;
|
|
25
|
+
/**
|
|
26
|
+
* Понятная фраза шага по его состоянию. Порядок: фраза приложения (`stepPhrases`), запасная фраза слоя поведения
|
|
27
|
+
* (`fallback`, например у помощника), название инструмента от приложения (`title`), общая фраза словаря.
|
|
28
|
+
* `unfinished` — ответ закончился, а вызов так и остался «идёт» («Стоп», обрыв): «Делаю календарь — не закончил».
|
|
29
|
+
*/
|
|
30
|
+
export declare function stepPhraseOf(call: StepCall & {
|
|
31
|
+
title?: string;
|
|
32
|
+
}, { phrases, labels, fallback, unfinished, }: {
|
|
33
|
+
phrases?: StepPhrases | undefined;
|
|
34
|
+
labels: WorkViewLabels;
|
|
35
|
+
fallback?: StepPhraseText | undefined;
|
|
36
|
+
unfinished?: boolean;
|
|
37
|
+
}): string;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { WorkViewLabels } from "../labels.js";
|
|
2
|
+
import type { StepCall, StepPhrases, StepPhraseText } from "./step-phrases.js";
|
|
3
|
+
/** Шаг работы: размышление модели или вызов инструмента (`title` — название от приложения, `fallback` — запасные фразы). */
|
|
4
|
+
export type WorkStep = {
|
|
5
|
+
kind: "thinking";
|
|
6
|
+
} | {
|
|
7
|
+
kind: "tool";
|
|
8
|
+
call: StepCall;
|
|
9
|
+
title?: string;
|
|
10
|
+
fallback?: StepPhraseText;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Часть ответа для раскладки: то, что видно как обычно (`blank` — пустой текст, модель только начала писать), или шаг
|
|
14
|
+
* работы. `key` шага — ключ части ответа: по первому шагу группы хранится раскрытие свёрнутой строки.
|
|
15
|
+
*/
|
|
16
|
+
export type AnswerEntry<Node> = {
|
|
17
|
+
kind: "shown";
|
|
18
|
+
node: Node;
|
|
19
|
+
blank?: boolean;
|
|
20
|
+
} | {
|
|
21
|
+
kind: "step";
|
|
22
|
+
key: string;
|
|
23
|
+
step: WorkStep;
|
|
24
|
+
};
|
|
25
|
+
/** Строка списка шагов. */
|
|
26
|
+
export interface WorkStepLine {
|
|
27
|
+
phrase: string;
|
|
28
|
+
failed: boolean;
|
|
29
|
+
}
|
|
30
|
+
/** Раскладка ответа в простом виде: видимые части, живая строка последней группы, свёрнутые группы. */
|
|
31
|
+
export type WorkLayoutItem<Node> = {
|
|
32
|
+
kind: "shown";
|
|
33
|
+
node: Node;
|
|
34
|
+
} | {
|
|
35
|
+
kind: "live";
|
|
36
|
+
key: string;
|
|
37
|
+
phrase: string;
|
|
38
|
+
} | {
|
|
39
|
+
kind: "done";
|
|
40
|
+
key: string;
|
|
41
|
+
steps: WorkStepLine[];
|
|
42
|
+
count: number;
|
|
43
|
+
};
|
|
44
|
+
interface LayoutOptions {
|
|
45
|
+
/** Ответ ещё пишется: последняя группа шагов — живая строка. */
|
|
46
|
+
streaming: boolean;
|
|
47
|
+
phrases?: StepPhrases | undefined;
|
|
48
|
+
labels: WorkViewLabels;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Простой вид: подряд идущие шаги (размышления и вызовы) — одна группа; пустой текст между ними группу не рвёт и
|
|
52
|
+
* ставится после неё. Последняя группа идущего ответа, после которой ничего не видно, — живая строка с текущим шагом.
|
|
53
|
+
* Остальные — свёрнутые «Сделано N шагов» с понятными фразами; одинаковые фразы подряд — одна строка «… ×N», группа из
|
|
54
|
+
* одних размышлений не показывается. Вызов, оставшийся «идёт» в законченном ответе («Стоп», обрыв), — «не закончил».
|
|
55
|
+
*/
|
|
56
|
+
export declare function workLayoutOf<Node>(entries: AnswerEntry<Node>[], { streaming, phrases, labels }: LayoutOptions): WorkLayoutItem<Node>[];
|
|
57
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ExpandedParts } from "../expanded-parts.js";
|
|
2
|
+
import type { ChatSkin } from "../skin-contract.js";
|
|
3
|
+
import type { WorkLayoutItem } from "./work-layout.js";
|
|
4
|
+
/**
|
|
5
|
+
* Живая строка или свёрнутые шаги простого вида. Раскрытие — в хранилище чата под своим ключом (`…:work`), отдельно от
|
|
6
|
+
* раскрытия мыслей и строк подробного вида. Скин без `WorkSteps` (до версии 23) получает строку `ToolCallRow`: фраза
|
|
7
|
+
* в `title`, входа нет, а результат — список понятных фраз текстом, по строке на шаг. Ни кода, ни путей.
|
|
8
|
+
*/
|
|
9
|
+
export declare function WorkStepsPart({ skin, expanded, item, }: {
|
|
10
|
+
skin: ChatSkin;
|
|
11
|
+
expanded: ExpandedParts;
|
|
12
|
+
item: Exclude<WorkLayoutItem<unknown>, {
|
|
13
|
+
kind: "shown";
|
|
14
|
+
}>;
|
|
15
|
+
}): import("react").JSX.Element;
|
package/package.json
CHANGED
|
@@ -1,6 +1,56 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ykurilov/agent-chat-react",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.56.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md",
|
|
10
|
+
"CHANGELOG.md"
|
|
11
|
+
],
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"@ykurilov/agent-chat-source": "./src/index.ts",
|
|
15
|
+
"types": "./dist/types/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./panel": {
|
|
19
|
+
"@ykurilov/agent-chat-source": "./src/agent-panel/index.ts",
|
|
20
|
+
"types": "./dist/types/agent-panel/index.d.ts",
|
|
21
|
+
"import": "./dist/panel.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=22"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"registry": "https://registry.npmjs.org",
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/ykurilov/agent-chat-sdk.git",
|
|
34
|
+
"directory": "packages/react"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@ai-sdk/react": "4.0.125",
|
|
38
|
+
"ai": "7.0.122",
|
|
39
|
+
"virtua": "0.52.8"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"react": "^19.3.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@testing-library/react": "^16.3.3",
|
|
46
|
+
"@types/react": "^19.3.0",
|
|
47
|
+
"@types/react-dom": "^19.3.0",
|
|
48
|
+
"jsdom": "^30.1.1",
|
|
49
|
+
"react": "^19.3.0",
|
|
50
|
+
"react-dom": "^19.3.0"
|
|
51
|
+
},
|
|
52
|
+
"scripts": {
|
|
53
|
+
"build": "node ../../scripts/build-package.mjs",
|
|
54
|
+
"typecheck": "tsc -p tsconfig.json"
|
|
55
|
+
}
|
|
6
56
|
}
|