@agent-native/toolkit 0.217.0 → 0.218.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/agent-native.eject.json +21 -0
- package/dist/app/agent-page/AgentContextTab.d.ts.map +1 -1
- package/dist/app/agent-page/AgentContextTab.js +1 -0
- package/dist/app/agent-page/AgentContextTab.js.map +1 -1
- package/dist/app/agentkit/react/components.d.ts.map +1 -1
- package/dist/app/agentkit/react/components.js +1 -1
- package/dist/app/agentkit/react/components.js.map +1 -1
- package/dist/app/agentkit/react/context.d.ts +4 -1
- package/dist/app/agentkit/react/context.d.ts.map +1 -1
- package/dist/app/agentkit/react/context.js +3 -1
- package/dist/app/agentkit/react/context.js.map +1 -1
- package/dist/app/agentkit/react/data-chart-layout.d.ts +30 -0
- package/dist/app/agentkit/react/data-chart-layout.d.ts.map +1 -0
- package/dist/app/agentkit/react/data-chart-layout.js +2 -0
- package/dist/app/agentkit/react/data-chart-layout.js.map +1 -0
- package/dist/app/agentkit/react/index.d.ts +1 -0
- package/dist/app/agentkit/react/index.d.ts.map +1 -1
- package/dist/app/agentkit/react/index.js +1 -0
- package/dist/app/agentkit/react/index.js.map +1 -1
- package/dist/app/agentkit/react/root.d.ts +3 -1
- package/dist/app/agentkit/react/root.d.ts.map +1 -1
- package/dist/app/agentkit/react/root.js +2 -2
- package/dist/app/agentkit/react/root.js.map +1 -1
- package/dist/app/agentkit/react/styles.css +18 -0
- package/dist/app/agentkit/react/transcript-layout.d.ts +2 -0
- package/dist/app/agentkit/react/transcript-layout.d.ts.map +1 -1
- package/dist/app/agentkit/react/transcript-layout.js.map +1 -1
- package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
- package/dist/app/chat/AgentKitAssistantChat.js +2 -2
- package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
- package/dist/app/chat/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/app/chat/MultiTabAssistantChat.js +51 -93
- package/dist/app/chat/MultiTabAssistantChat.js.map +1 -1
- package/dist/app/chat/agentkit-chat/action-widget.d.ts.map +1 -1
- package/dist/app/chat/agentkit-chat/action-widget.js +3 -1
- package/dist/app/chat/agentkit-chat/action-widget.js.map +1 -1
- package/dist/app/chat/agentkit-chat/rail.d.ts +1 -1
- package/dist/app/chat/agentkit-chat/rail.d.ts.map +1 -1
- package/dist/app/chat/agentkit-chat/rail.js +1 -1
- package/dist/app/chat/agentkit-chat/rail.js.map +1 -1
- package/dist/app/chat/chat/index.d.ts +2 -1
- package/dist/app/chat/chat/index.d.ts.map +1 -1
- package/dist/app/chat/chat/index.js +1 -1
- package/dist/app/chat/chat/index.js.map +1 -1
- package/dist/app/chat/chat/surface-types.d.ts +3 -0
- package/dist/app/chat/chat/surface-types.d.ts.map +1 -1
- package/dist/app/chat/chat/surface-types.js.map +1 -1
- package/dist/app/chat/chat/tool-call-display.d.ts +3 -1
- package/dist/app/chat/chat/tool-call-display.d.ts.map +1 -1
- package/dist/app/chat/chat/tool-call-display.js +4 -3
- package/dist/app/chat/chat/tool-call-display.js.map +1 -1
- package/dist/app/chat/chat/tool-render-registry.d.ts +2 -0
- package/dist/app/chat/chat/tool-render-registry.d.ts.map +1 -1
- package/dist/app/chat/chat/tool-render-registry.js.map +1 -1
- package/dist/app/chat/chat/widgets/DataChartRenderer.d.ts +3 -1
- package/dist/app/chat/chat/widgets/DataChartRenderer.d.ts.map +1 -1
- package/dist/app/chat/chat/widgets/DataChartRenderer.js +116 -26
- package/dist/app/chat/chat/widgets/DataChartRenderer.js.map +1 -1
- package/dist/app/chat/chat/widgets/DataChartWidget.d.ts +3 -1
- package/dist/app/chat/chat/widgets/DataChartWidget.d.ts.map +1 -1
- package/dist/app/chat/chat/widgets/DataChartWidget.js +21 -2
- package/dist/app/chat/chat/widgets/DataChartWidget.js.map +1 -1
- package/dist/app/chat/chat/widgets/DataInsightsWidget.d.ts +3 -1
- package/dist/app/chat/chat/widgets/DataInsightsWidget.d.ts.map +1 -1
- package/dist/app/chat/chat/widgets/DataInsightsWidget.js +2 -2
- package/dist/app/chat/chat/widgets/DataInsightsWidget.js.map +1 -1
- package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.d.ts +1 -1
- package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.d.ts.map +1 -1
- package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.js +3 -1
- package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.js.map +1 -1
- package/dist/app/chat/chat/widgets/builtin-tool-renderers.d.ts.map +1 -1
- package/dist/app/chat/chat/widgets/builtin-tool-renderers.js +2 -2
- package/dist/app/chat/chat/widgets/builtin-tool-renderers.js.map +1 -1
- package/dist/app/chat/chat-first/chat-history.d.ts +13 -2
- package/dist/app/chat/chat-first/chat-history.d.ts.map +1 -1
- package/dist/app/chat/chat-first/chat-history.js +24 -3
- package/dist/app/chat/chat-first/chat-history.js.map +1 -1
- package/dist/app/chat/ownership-history/ChatOwnerAvatar.d.ts +6 -0
- package/dist/app/chat/ownership-history/ChatOwnerAvatar.d.ts.map +1 -0
- package/dist/app/chat/ownership-history/ChatOwnerAvatar.js +9 -0
- package/dist/app/chat/ownership-history/ChatOwnerAvatar.js.map +1 -0
- package/dist/app/chat/ownership-history/index.d.ts +11 -0
- package/dist/app/chat/ownership-history/index.d.ts.map +1 -0
- package/dist/app/chat/ownership-history/index.js +22 -0
- package/dist/app/chat/ownership-history/index.js.map +1 -0
- package/dist/app/chat/ownership-history/rows.d.ts +27 -0
- package/dist/app/chat/ownership-history/rows.d.ts.map +1 -0
- package/dist/app/chat/ownership-history/rows.js +101 -0
- package/dist/app/chat/ownership-history/rows.js.map +1 -0
- package/dist/app/chat/ownership-history/useOwnershipChatHistory.d.ts +52 -0
- package/dist/app/chat/ownership-history/useOwnershipChatHistory.d.ts.map +1 -0
- package/dist/app/chat/ownership-history/useOwnershipChatHistory.js +497 -0
- package/dist/app/chat/ownership-history/useOwnershipChatHistory.js.map +1 -0
- package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ar-SA.js +3 -0
- package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
- package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/de-DE.js +3 -0
- package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
- package/dist/app/i18n/catalogs/en-US.d.ts +3 -0
- package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/en-US.js +3 -0
- package/dist/app/i18n/catalogs/en-US.js.map +1 -1
- package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/es-ES.js +3 -0
- package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
- package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/fr-FR.js +3 -0
- package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
- package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/hi-IN.js +3 -0
- package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
- package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ja-JP.js +3 -0
- package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
- package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ko-KR.js +3 -0
- package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
- package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/pt-BR.js +3 -0
- package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
- package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/zh-CN.js +3 -0
- package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
- package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/zh-TW.js +3 -0
- package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
- package/dist/app/sharing/ShareButton.d.ts.map +1 -1
- package/dist/app/sharing/ShareButton.js +9 -8
- package/dist/app/sharing/ShareButton.js.map +1 -1
- package/dist/chat-history/ChatHistoryList.d.ts +16 -3
- package/dist/chat-history/ChatHistoryList.d.ts.map +1 -1
- package/dist/chat-history/ChatHistoryList.js +25 -15
- package/dist/chat-history/ChatHistoryList.js.map +1 -1
- package/dist/chat-history.css +109 -9
- package/package.json +10 -3
- package/src/app/agent-page/AgentContextTab.spec.ts +50 -2
- package/src/app/agent-page/AgentContextTab.tsx +1 -0
- package/src/app/agentkit/react/components.interaction.spec.tsx +2 -0
- package/src/app/agentkit/react/components.spec.tsx +4 -1
- package/src/app/agentkit/react/components.tsx +3 -0
- package/src/app/agentkit/react/context.tsx +6 -0
- package/src/app/agentkit/react/data-chart-layout.ts +25 -0
- package/src/app/agentkit/react/index.ts +1 -0
- package/src/app/agentkit/react/root.tsx +4 -0
- package/src/app/agentkit/react/styles.css +18 -0
- package/src/app/agentkit/react/transcript-layout.ts +2 -0
- package/src/app/chat/AgentKitAssistantChat.tsx +2 -0
- package/src/app/chat/MultiTabAssistantChat.spec.tsx +270 -3
- package/src/app/chat/MultiTabAssistantChat.tsx +79 -156
- package/src/app/chat/agentkit-chat/action-widget.tsx +3 -0
- package/src/app/chat/agentkit-chat/rail.ts +11 -0
- package/src/app/chat/chat/index.ts +10 -0
- package/src/app/chat/chat/surface-types.ts +3 -0
- package/src/app/chat/chat/tool-call-display.spec.tsx +29 -0
- package/src/app/chat/chat/tool-call-display.tsx +7 -0
- package/src/app/chat/chat/tool-render-registry.tsx +3 -0
- package/src/app/chat/chat/widgets/DataChartRenderer.spec.tsx +377 -17
- package/src/app/chat/chat/widgets/DataChartRenderer.tsx +232 -63
- package/src/app/chat/chat/widgets/DataChartWidget.spec.tsx +67 -0
- package/src/app/chat/chat/widgets/DataChartWidget.tsx +39 -5
- package/src/app/chat/chat/widgets/DataInsightsWidget.tsx +13 -2
- package/src/app/chat/chat/widgets/DataWidgetDisplayControls.tsx +6 -4
- package/src/app/chat/chat/widgets/builtin-tool-renderers.tsx +5 -1
- package/src/app/chat/chat-first/chat-history.spec.tsx +79 -0
- package/src/app/chat/chat-first/chat-history.tsx +75 -22
- package/src/app/chat/ownership-history/ChatOwnerAvatar.tsx +27 -0
- package/src/app/chat/ownership-history/index.tsx +67 -0
- package/src/app/chat/ownership-history/ownership-history.spec.tsx +3146 -0
- package/src/app/chat/ownership-history/rows.ts +156 -0
- package/src/app/chat/ownership-history/useOwnershipChatHistory.ts +709 -0
- package/src/app/i18n/catalogs/ar-SA.ts +3 -0
- package/src/app/i18n/catalogs/de-DE.ts +3 -0
- package/src/app/i18n/catalogs/en-US.ts +3 -0
- package/src/app/i18n/catalogs/es-ES.ts +3 -0
- package/src/app/i18n/catalogs/fr-FR.ts +3 -0
- package/src/app/i18n/catalogs/hi-IN.ts +3 -0
- package/src/app/i18n/catalogs/ja-JP.ts +3 -0
- package/src/app/i18n/catalogs/ko-KR.ts +3 -0
- package/src/app/i18n/catalogs/pt-BR.ts +3 -0
- package/src/app/i18n/catalogs/zh-CN.ts +3 -0
- package/src/app/i18n/catalogs/zh-TW.ts +3 -0
- package/src/app/sharing/ShareButton.tsx +12 -10
- package/src/chat-history/ChatHistoryList.spec.tsx +51 -0
- package/src/chat-history/ChatHistoryList.tsx +87 -26
- package/src/chat-history/ChatHistoryRailSections.spec.tsx +12 -4
- package/src/chat-history.css +109 -9
|
@@ -0,0 +1,709 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useChatThreadList,
|
|
3
|
+
type ChatThreadListRow,
|
|
4
|
+
type UseChatThreadListOptions,
|
|
5
|
+
} from "@agent-native/core/client/agent-chat";
|
|
6
|
+
import { agentNativePath } from "@agent-native/core/client/api-path";
|
|
7
|
+
import {
|
|
8
|
+
DEFAULT_LOCALE,
|
|
9
|
+
useOptionalLocale,
|
|
10
|
+
useT,
|
|
11
|
+
} from "@agent-native/core/client/i18n";
|
|
12
|
+
import type { ChatHistoryItem } from "@agent-native/toolkit/chat-history/ChatHistoryList";
|
|
13
|
+
import type { ChatHistoryRailSection } from "@agent-native/toolkit/chat-history/ChatHistoryRail";
|
|
14
|
+
import type { ChatHistoryRailSectionControllerLabels } from "@agent-native/toolkit/chat-history/useChatHistoryRailController";
|
|
15
|
+
import { writeClipboardText } from "@agent-native/toolkit/clipboard";
|
|
16
|
+
import {
|
|
17
|
+
useCallback,
|
|
18
|
+
useEffect,
|
|
19
|
+
useLayoutEffect,
|
|
20
|
+
useMemo,
|
|
21
|
+
useRef,
|
|
22
|
+
useState,
|
|
23
|
+
type ReactNode,
|
|
24
|
+
} from "react";
|
|
25
|
+
import { toast } from "sonner";
|
|
26
|
+
|
|
27
|
+
import {
|
|
28
|
+
chatThreadToHistoryItem,
|
|
29
|
+
ownDraftToHistoryItem,
|
|
30
|
+
type OwnDraftRow,
|
|
31
|
+
} from "./rows.js";
|
|
32
|
+
|
|
33
|
+
export type OwnershipChatHistoryMutationKind = "pin" | "rename" | "archive";
|
|
34
|
+
export type OwnershipChatHistorySection = "pinned" | "mine" | "shared";
|
|
35
|
+
|
|
36
|
+
export interface UseOwnershipChatHistoryOptions extends Omit<
|
|
37
|
+
UseChatThreadListOptions,
|
|
38
|
+
"ownership"
|
|
39
|
+
> {
|
|
40
|
+
activeId?: string | null;
|
|
41
|
+
minePreviewCount?: number;
|
|
42
|
+
sharedPreviewCount?: number;
|
|
43
|
+
pinned?: boolean | { label?: ReactNode };
|
|
44
|
+
localMineRows?: readonly OwnDraftRow[];
|
|
45
|
+
decorateItem?: (
|
|
46
|
+
item: ChatHistoryItem,
|
|
47
|
+
row: ChatThreadListRow | OwnDraftRow,
|
|
48
|
+
context: { section: OwnershipChatHistorySection },
|
|
49
|
+
) => ChatHistoryItem;
|
|
50
|
+
mutations?: {
|
|
51
|
+
pin?: (id: string, pinned: boolean) => Promise<boolean>;
|
|
52
|
+
rename?: (id: string, title: string) => Promise<boolean>;
|
|
53
|
+
archive?: (id: string) => Promise<boolean>;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* The URL that opens a thread, resolved against the current page; enables
|
|
57
|
+
* Copy link on every row. Router paths need `appPath()` for the base path.
|
|
58
|
+
*/
|
|
59
|
+
getThreadUrl?: (id: string) => string;
|
|
60
|
+
onMutationFailed?: (
|
|
61
|
+
kind: OwnershipChatHistoryMutationKind,
|
|
62
|
+
id: string,
|
|
63
|
+
cause?: unknown,
|
|
64
|
+
) => void;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface OwnershipChatHistoryListProps {
|
|
68
|
+
onTogglePin?: (id: string) => Promise<boolean>;
|
|
69
|
+
onRename?: (id: string, title: string) => Promise<boolean>;
|
|
70
|
+
onDelete?: (id: string) => Promise<boolean>;
|
|
71
|
+
onCopyLink?: (id: string) => Promise<void>;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface UseOwnershipChatHistoryResult {
|
|
75
|
+
sections: ChatHistoryRailSection[];
|
|
76
|
+
railLabels: { sections: ChatHistoryRailSectionControllerLabels };
|
|
77
|
+
listProps: OwnershipChatHistoryListProps;
|
|
78
|
+
mineRows: ChatThreadListRow[];
|
|
79
|
+
sharedRows: ChatThreadListRow[];
|
|
80
|
+
loading: boolean;
|
|
81
|
+
error: Error | null;
|
|
82
|
+
refresh: () => Promise<void>;
|
|
83
|
+
findMine: (id: string) => ChatThreadListRow | OwnDraftRow | undefined;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
interface OverrideValues {
|
|
87
|
+
title: string;
|
|
88
|
+
pinned: boolean;
|
|
89
|
+
hidden: boolean;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
interface FieldIntent<Value> {
|
|
93
|
+
token: number;
|
|
94
|
+
value: Value;
|
|
95
|
+
mineAtStart: readonly ChatThreadListRow[];
|
|
96
|
+
sharedAtStart: readonly ChatThreadListRow[];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
interface FieldState<Value> {
|
|
100
|
+
latestToken: number;
|
|
101
|
+
inFlight: ReadonlyMap<number, FieldIntent<Value>>;
|
|
102
|
+
// A reconciled success remains a watermark until older writes finish.
|
|
103
|
+
successful?: { intent: FieldIntent<Value>; reconciled: boolean };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
type OverrideField = keyof OverrideValues;
|
|
107
|
+
type Override = {
|
|
108
|
+
[Field in OverrideField]?: FieldState<OverrideValues[Field]>;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const OVERRIDE_FIELDS = ["title", "pinned", "hidden"] as const;
|
|
112
|
+
|
|
113
|
+
function isPersistedOwner(row: ChatThreadListRow | OwnDraftRow | undefined) {
|
|
114
|
+
return (
|
|
115
|
+
!!row &&
|
|
116
|
+
("accessBasis" in row
|
|
117
|
+
? row.accessBasis === "owner"
|
|
118
|
+
: row.persisted === true)
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Accepted writes outlive views, including a replacement mount for this resource.
|
|
123
|
+
const writeTails = new Map<string, Promise<void>>();
|
|
124
|
+
|
|
125
|
+
function persistInOrder(key: string, persist: () => Promise<boolean>) {
|
|
126
|
+
const previous = writeTails.get(key);
|
|
127
|
+
let release!: () => void;
|
|
128
|
+
const tail = new Promise<void>((resolve) => {
|
|
129
|
+
release = resolve;
|
|
130
|
+
});
|
|
131
|
+
writeTails.set(key, tail);
|
|
132
|
+
const run = async () => {
|
|
133
|
+
try {
|
|
134
|
+
return await persist();
|
|
135
|
+
} finally {
|
|
136
|
+
if (writeTails.get(key) === tail) writeTails.delete(key);
|
|
137
|
+
release();
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
return previous ? previous.then(run) : run();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function projectedIntent<Value>(state: FieldState<Value> | undefined) {
|
|
144
|
+
if (!state) return undefined;
|
|
145
|
+
let pending: FieldIntent<Value> | undefined;
|
|
146
|
+
const watermark = state.successful?.intent.token ?? -Infinity;
|
|
147
|
+
for (const intent of state.inFlight.values()) {
|
|
148
|
+
if (intent.token > watermark && (!pending || intent.token > pending.token))
|
|
149
|
+
pending = intent;
|
|
150
|
+
}
|
|
151
|
+
return (
|
|
152
|
+
pending ??
|
|
153
|
+
(state.successful?.reconciled ? undefined : state.successful?.intent)
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function successfulIntents(rows: ReadonlyMap<string, Override>) {
|
|
158
|
+
return [...rows].flatMap(([id, override]) =>
|
|
159
|
+
OVERRIDE_FIELDS.flatMap((field) => {
|
|
160
|
+
const successful = override[field]?.successful;
|
|
161
|
+
return successful && !successful.reconciled
|
|
162
|
+
? [{ id, field, intent: successful.intent }]
|
|
163
|
+
: [];
|
|
164
|
+
}),
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function withField<Field extends OverrideField>(
|
|
169
|
+
rows: Map<string, Override>,
|
|
170
|
+
id: string,
|
|
171
|
+
field: Field,
|
|
172
|
+
state: FieldState<OverrideValues[Field]>,
|
|
173
|
+
): Map<string, Override> {
|
|
174
|
+
const remaining = { ...rows.get(id), [field]: state };
|
|
175
|
+
if (
|
|
176
|
+
state.inFlight.size === 0 &&
|
|
177
|
+
(!state.successful || state.successful.reconciled)
|
|
178
|
+
)
|
|
179
|
+
delete remaining[field];
|
|
180
|
+
const next = new Map(rows);
|
|
181
|
+
if (OVERRIDE_FIELDS.some((field) => remaining[field]))
|
|
182
|
+
next.set(id, remaining);
|
|
183
|
+
else next.delete(id);
|
|
184
|
+
return next;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function reconcileIntent(
|
|
188
|
+
rows: Map<string, Override>,
|
|
189
|
+
id: string,
|
|
190
|
+
field: OverrideField,
|
|
191
|
+
token: number,
|
|
192
|
+
): Map<string, Override> {
|
|
193
|
+
const state = rows.get(id)?.[field];
|
|
194
|
+
if (state?.successful?.intent.token !== token) return rows;
|
|
195
|
+
return withField(rows, id, field, {
|
|
196
|
+
...state,
|
|
197
|
+
successful: { ...state.successful, reconciled: true },
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function matches(
|
|
202
|
+
id: string,
|
|
203
|
+
field: OverrideField,
|
|
204
|
+
intent: FieldIntent<string | boolean>,
|
|
205
|
+
mine: readonly ChatThreadListRow[],
|
|
206
|
+
shared: readonly ChatThreadListRow[],
|
|
207
|
+
): boolean {
|
|
208
|
+
if (mine === intent.mineAtStart) return false;
|
|
209
|
+
const row = mine.find((row) => row.id === id);
|
|
210
|
+
if (field === "hidden")
|
|
211
|
+
return (
|
|
212
|
+
shared !== intent.sharedAtStart &&
|
|
213
|
+
!row &&
|
|
214
|
+
!shared.some((row) => row.id === id)
|
|
215
|
+
);
|
|
216
|
+
return (
|
|
217
|
+
!!row &&
|
|
218
|
+
(field === "title"
|
|
219
|
+
? intent.value === row.title
|
|
220
|
+
: intent.value === (row.pinnedAt != null))
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export function useOwnershipChatHistory(
|
|
225
|
+
options: UseOwnershipChatHistoryOptions = {},
|
|
226
|
+
): UseOwnershipChatHistoryResult {
|
|
227
|
+
const {
|
|
228
|
+
apiUrl,
|
|
229
|
+
scope,
|
|
230
|
+
includeExternal,
|
|
231
|
+
query,
|
|
232
|
+
pageSize,
|
|
233
|
+
enabled = true,
|
|
234
|
+
activeId,
|
|
235
|
+
pinned,
|
|
236
|
+
localMineRows,
|
|
237
|
+
decorateItem,
|
|
238
|
+
minePreviewCount = 5,
|
|
239
|
+
sharedPreviewCount = 5,
|
|
240
|
+
} = options;
|
|
241
|
+
const endpoint = apiUrl ?? agentNativePath("/_agent-native/agent-chat");
|
|
242
|
+
const normalizedQuery = query?.trim() ?? "";
|
|
243
|
+
const listOptions = {
|
|
244
|
+
apiUrl: endpoint,
|
|
245
|
+
scope,
|
|
246
|
+
includeExternal,
|
|
247
|
+
query: normalizedQuery,
|
|
248
|
+
pageSize,
|
|
249
|
+
enabled,
|
|
250
|
+
refreshOnThreadUpdates: false,
|
|
251
|
+
};
|
|
252
|
+
const mine = useChatThreadList({ ...listOptions, ownership: "mine" });
|
|
253
|
+
const shared = useChatThreadList({ ...listOptions, ownership: "shared" });
|
|
254
|
+
const t = useT();
|
|
255
|
+
const locale = useOptionalLocale()?.locale ?? DEFAULT_LOCALE;
|
|
256
|
+
const scopeKey = JSON.stringify([
|
|
257
|
+
endpoint,
|
|
258
|
+
scope?.type,
|
|
259
|
+
scope?.id,
|
|
260
|
+
includeExternal,
|
|
261
|
+
normalizedQuery,
|
|
262
|
+
pageSize,
|
|
263
|
+
enabled,
|
|
264
|
+
]);
|
|
265
|
+
const generation = useMemo(
|
|
266
|
+
() => ({
|
|
267
|
+
view: null as { active: boolean } | null,
|
|
268
|
+
rows: new Map<string, Override>(),
|
|
269
|
+
dirty: false,
|
|
270
|
+
needsRefresh: false,
|
|
271
|
+
inFlight: 0,
|
|
272
|
+
writes: 0,
|
|
273
|
+
threadUpdates: false,
|
|
274
|
+
lastRefresh: -Infinity,
|
|
275
|
+
}),
|
|
276
|
+
[scopeKey],
|
|
277
|
+
);
|
|
278
|
+
const generationRef = useRef(generation);
|
|
279
|
+
generationRef.current = generation;
|
|
280
|
+
const [revision, publish] = useState(0);
|
|
281
|
+
const overrides = generation.rows;
|
|
282
|
+
const tokenRef = useRef(0);
|
|
283
|
+
const latest = useRef({ mine, shared, options });
|
|
284
|
+
latest.current = { mine, shared, options };
|
|
285
|
+
|
|
286
|
+
const current = useCallback(
|
|
287
|
+
() =>
|
|
288
|
+
generation.view?.active === true && generationRef.current === generation,
|
|
289
|
+
[generation],
|
|
290
|
+
);
|
|
291
|
+
const updateOverrides = useCallback(
|
|
292
|
+
(update: (rows: Map<string, Override>) => Map<string, Override>) => {
|
|
293
|
+
// Activity detaches effects without releasing this generation's mutations.
|
|
294
|
+
const next = update(generation.rows);
|
|
295
|
+
if (next === generation.rows) return;
|
|
296
|
+
generation.rows = next;
|
|
297
|
+
if (current()) publish((value) => value + 1);
|
|
298
|
+
else generation.dirty = true;
|
|
299
|
+
},
|
|
300
|
+
[current, generation],
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
useLayoutEffect(() => {
|
|
304
|
+
// Reactivation must not revive permission for pre-hide continuations.
|
|
305
|
+
const view = { active: true };
|
|
306
|
+
generation.view = view;
|
|
307
|
+
if (generation.dirty) {
|
|
308
|
+
generation.dirty = false;
|
|
309
|
+
publish((value) => value + 1);
|
|
310
|
+
}
|
|
311
|
+
if (successfulIntents(generation.rows).length)
|
|
312
|
+
generation.needsRefresh = true;
|
|
313
|
+
return () => {
|
|
314
|
+
view.active = false;
|
|
315
|
+
};
|
|
316
|
+
}, [generation]);
|
|
317
|
+
|
|
318
|
+
const refreshWithResults = useCallback(async () => {
|
|
319
|
+
if (!enabled || !current()) return ["disabled", "disabled"] as const;
|
|
320
|
+
const view = generation.view;
|
|
321
|
+
const settled = successfulIntents(generation.rows);
|
|
322
|
+
generation.threadUpdates = false;
|
|
323
|
+
generation.inFlight += 1;
|
|
324
|
+
try {
|
|
325
|
+
const outcomes = await Promise.all([
|
|
326
|
+
latest.current.mine.refreshWithResult(),
|
|
327
|
+
latest.current.shared.refreshWithResult(),
|
|
328
|
+
]);
|
|
329
|
+
if (
|
|
330
|
+
current() &&
|
|
331
|
+
generation.view === view &&
|
|
332
|
+
settled.length &&
|
|
333
|
+
outcomes.every((outcome) => outcome === "success")
|
|
334
|
+
) {
|
|
335
|
+
updateOverrides((rows) => {
|
|
336
|
+
let next = rows;
|
|
337
|
+
for (const { id, field, intent } of settled) {
|
|
338
|
+
next = reconcileIntent(next, id, field, intent.token);
|
|
339
|
+
}
|
|
340
|
+
return next;
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
return outcomes;
|
|
344
|
+
} finally {
|
|
345
|
+
generation.inFlight -= 1;
|
|
346
|
+
generation.lastRefresh = Date.now();
|
|
347
|
+
if (
|
|
348
|
+
current() &&
|
|
349
|
+
(generation.needsRefresh || generation.threadUpdates) &&
|
|
350
|
+
generation.inFlight === 0
|
|
351
|
+
)
|
|
352
|
+
publish((value) => value + 1);
|
|
353
|
+
}
|
|
354
|
+
}, [current, enabled, generation, updateOverrides]);
|
|
355
|
+
const refresh = useCallback(async () => {
|
|
356
|
+
await refreshWithResults();
|
|
357
|
+
}, [refreshWithResults]);
|
|
358
|
+
|
|
359
|
+
useEffect(() => {
|
|
360
|
+
if (!enabled || typeof window === "undefined") return;
|
|
361
|
+
const refreshIfDue = () => {
|
|
362
|
+
if (generation.inFlight || Date.now() - generation.lastRefresh < 10_000)
|
|
363
|
+
return;
|
|
364
|
+
void refresh();
|
|
365
|
+
};
|
|
366
|
+
const onRunEnd = (event: Event) => {
|
|
367
|
+
if (
|
|
368
|
+
(event as CustomEvent<{ isRunning?: boolean }>).detail?.isRunning ===
|
|
369
|
+
false
|
|
370
|
+
)
|
|
371
|
+
refreshIfDue();
|
|
372
|
+
};
|
|
373
|
+
const onUpdated = () => {
|
|
374
|
+
generation.threadUpdates = true;
|
|
375
|
+
if (!generation.writes && !generation.inFlight) void refresh();
|
|
376
|
+
};
|
|
377
|
+
window.addEventListener("focus", refreshIfDue);
|
|
378
|
+
window.addEventListener("agentNative.chatRunning", onRunEnd);
|
|
379
|
+
window.addEventListener("agent-chat:threads-updated", onUpdated);
|
|
380
|
+
return () => {
|
|
381
|
+
window.removeEventListener("focus", refreshIfDue);
|
|
382
|
+
window.removeEventListener("agentNative.chatRunning", onRunEnd);
|
|
383
|
+
window.removeEventListener("agent-chat:threads-updated", onUpdated);
|
|
384
|
+
};
|
|
385
|
+
}, [enabled, generation, refresh]);
|
|
386
|
+
|
|
387
|
+
useEffect(() => {
|
|
388
|
+
if (mine.error || shared.error) return;
|
|
389
|
+
const reconciled = successfulIntents(generation.rows).filter(
|
|
390
|
+
({ id, field, intent }) =>
|
|
391
|
+
matches(id, field, intent, mine.threads, shared.threads),
|
|
392
|
+
);
|
|
393
|
+
if (reconciled.length === 0) return;
|
|
394
|
+
updateOverrides((rows) => {
|
|
395
|
+
let next = rows;
|
|
396
|
+
for (const { id, field, intent } of reconciled) {
|
|
397
|
+
next = reconcileIntent(next, id, field, intent.token);
|
|
398
|
+
}
|
|
399
|
+
return next;
|
|
400
|
+
});
|
|
401
|
+
}, [
|
|
402
|
+
mine.threads,
|
|
403
|
+
shared.threads,
|
|
404
|
+
mine.error,
|
|
405
|
+
shared.error,
|
|
406
|
+
generation,
|
|
407
|
+
updateOverrides,
|
|
408
|
+
]);
|
|
409
|
+
|
|
410
|
+
useEffect(() => {
|
|
411
|
+
if (
|
|
412
|
+
!enabled ||
|
|
413
|
+
!current() ||
|
|
414
|
+
(!generation.needsRefresh && !generation.threadUpdates) ||
|
|
415
|
+
generation.inFlight ||
|
|
416
|
+
generation.writes
|
|
417
|
+
)
|
|
418
|
+
return;
|
|
419
|
+
const needsRefresh =
|
|
420
|
+
generation.threadUpdates || successfulIntents(generation.rows).length > 0;
|
|
421
|
+
generation.needsRefresh = false;
|
|
422
|
+
if (needsRefresh) void refreshWithResults();
|
|
423
|
+
}, [current, enabled, generation, refreshWithResults, revision]);
|
|
424
|
+
|
|
425
|
+
const mineRows = enabled ? mine.threads : [];
|
|
426
|
+
const mineIds = new Set(mineRows.map((row) => row.id));
|
|
427
|
+
const sharedRows = enabled
|
|
428
|
+
? shared.threads.filter((row) => !mineIds.has(row.id))
|
|
429
|
+
: [];
|
|
430
|
+
const serverIds = new Set([...mineRows, ...sharedRows].map((row) => row.id));
|
|
431
|
+
const drafts = enabled
|
|
432
|
+
? (localMineRows ?? []).filter((row) => !serverIds.has(row.id))
|
|
433
|
+
: [];
|
|
434
|
+
const findMine = (id: string) =>
|
|
435
|
+
mineRows.find((row) => row.id === id && row.accessBasis === "owner") ??
|
|
436
|
+
drafts.find((row) => row.id === id);
|
|
437
|
+
|
|
438
|
+
const mutate = async <Field extends OverrideField>(
|
|
439
|
+
kind: OwnershipChatHistoryMutationKind,
|
|
440
|
+
id: string,
|
|
441
|
+
field: Field,
|
|
442
|
+
value: OverrideValues[Field],
|
|
443
|
+
persist: () => Promise<boolean>,
|
|
444
|
+
) => {
|
|
445
|
+
if (!enabled || !current() || !isPersistedOwner(findMine(id))) return false;
|
|
446
|
+
const view = generation.view;
|
|
447
|
+
const permitted = () => current() && generation.view === view;
|
|
448
|
+
const token = ++tokenRef.current;
|
|
449
|
+
generation.writes += 1;
|
|
450
|
+
const intent = {
|
|
451
|
+
value,
|
|
452
|
+
token,
|
|
453
|
+
mineAtStart: mine.threads,
|
|
454
|
+
sharedAtStart: shared.threads,
|
|
455
|
+
};
|
|
456
|
+
updateOverrides((rows) => {
|
|
457
|
+
const state = rows.get(id)?.[field];
|
|
458
|
+
return withField(rows, id, field, {
|
|
459
|
+
...state,
|
|
460
|
+
latestToken: token,
|
|
461
|
+
inFlight: new Map(state?.inFlight).set(token, intent),
|
|
462
|
+
});
|
|
463
|
+
});
|
|
464
|
+
const complete = (succeeded: boolean) => {
|
|
465
|
+
generation.writes -= 1;
|
|
466
|
+
let isLatest = false;
|
|
467
|
+
updateOverrides((rows) => {
|
|
468
|
+
const state = rows.get(id)?.[field];
|
|
469
|
+
if (!state?.inFlight.has(token))
|
|
470
|
+
throw new Error("Chat history mutation lost its in-flight intent.");
|
|
471
|
+
isLatest = state.latestToken === token;
|
|
472
|
+
const inFlight = new Map(state.inFlight);
|
|
473
|
+
inFlight.delete(token);
|
|
474
|
+
const successful =
|
|
475
|
+
succeeded &&
|
|
476
|
+
(!state.successful || token > state.successful.intent.token)
|
|
477
|
+
? { intent, reconciled: false }
|
|
478
|
+
: state.successful;
|
|
479
|
+
return withField(rows, id, field, { ...state, inFlight, successful });
|
|
480
|
+
});
|
|
481
|
+
return isLatest;
|
|
482
|
+
};
|
|
483
|
+
let succeeded: boolean;
|
|
484
|
+
try {
|
|
485
|
+
succeeded = await persistInOrder(
|
|
486
|
+
JSON.stringify([endpoint, id, field]),
|
|
487
|
+
persist,
|
|
488
|
+
);
|
|
489
|
+
} catch (cause) {
|
|
490
|
+
const isLatest = complete(false);
|
|
491
|
+
if (permitted() && isLatest)
|
|
492
|
+
latest.current.options.onMutationFailed?.(kind, id, cause);
|
|
493
|
+
return false;
|
|
494
|
+
}
|
|
495
|
+
if (!succeeded) {
|
|
496
|
+
const isLatest = complete(false);
|
|
497
|
+
if (permitted() && isLatest)
|
|
498
|
+
latest.current.options.onMutationFailed?.(kind, id);
|
|
499
|
+
return false;
|
|
500
|
+
}
|
|
501
|
+
complete(true);
|
|
502
|
+
if (!permitted()) {
|
|
503
|
+
generation.needsRefresh = true;
|
|
504
|
+
if (current()) publish((value) => value + 1);
|
|
505
|
+
return false;
|
|
506
|
+
}
|
|
507
|
+
const successful = generation.rows.get(id)?.[field]?.successful;
|
|
508
|
+
if (
|
|
509
|
+
successful?.intent.token === token &&
|
|
510
|
+
matches(
|
|
511
|
+
id,
|
|
512
|
+
field,
|
|
513
|
+
successful.intent,
|
|
514
|
+
latest.current.mine.threads,
|
|
515
|
+
latest.current.shared.threads,
|
|
516
|
+
) &&
|
|
517
|
+
!latest.current.mine.error &&
|
|
518
|
+
!latest.current.shared.error
|
|
519
|
+
) {
|
|
520
|
+
updateOverrides((rows) => reconcileIntent(rows, id, field, token));
|
|
521
|
+
return true;
|
|
522
|
+
}
|
|
523
|
+
// This request starts after persistence; an earlier notification can still
|
|
524
|
+
// be returning the pre-mutation window when the mutation resolves.
|
|
525
|
+
await refreshWithResults();
|
|
526
|
+
if (!permitted()) {
|
|
527
|
+
generation.needsRefresh = true;
|
|
528
|
+
if (current()) publish((value) => value + 1);
|
|
529
|
+
}
|
|
530
|
+
return permitted();
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
const listProps: OwnershipChatHistoryListProps = {};
|
|
534
|
+
if (options.mutations?.pin)
|
|
535
|
+
listProps.onTogglePin = async (id) => {
|
|
536
|
+
const persist = options.mutations!.pin!;
|
|
537
|
+
const row = findMine(id);
|
|
538
|
+
if (!row) return false;
|
|
539
|
+
const nextPinned = !(
|
|
540
|
+
projectedIntent(generation.rows.get(id)?.pinned)?.value ??
|
|
541
|
+
("pinnedAt" in row && row.pinnedAt != null)
|
|
542
|
+
);
|
|
543
|
+
return mutate("pin", id, "pinned", nextPinned, () =>
|
|
544
|
+
persist(id, nextPinned),
|
|
545
|
+
);
|
|
546
|
+
};
|
|
547
|
+
if (options.mutations?.rename)
|
|
548
|
+
listProps.onRename = (id, title) => {
|
|
549
|
+
const persist = options.mutations!.rename!;
|
|
550
|
+
const nextTitle = title.replace(/\s+/g, " ").trim().slice(0, 160);
|
|
551
|
+
return mutate("rename", id, "title", nextTitle, () =>
|
|
552
|
+
persist(id, nextTitle),
|
|
553
|
+
);
|
|
554
|
+
};
|
|
555
|
+
if (options.mutations?.archive)
|
|
556
|
+
listProps.onDelete = (id) => {
|
|
557
|
+
const persist = options.mutations!.archive!;
|
|
558
|
+
return mutate("archive", id, "hidden", true, () => persist(id));
|
|
559
|
+
};
|
|
560
|
+
if (options.getThreadUrl)
|
|
561
|
+
listProps.onCopyLink = async (id) => {
|
|
562
|
+
const url = new URL(
|
|
563
|
+
options.getThreadUrl!(id),
|
|
564
|
+
window.location.href,
|
|
565
|
+
).toString();
|
|
566
|
+
if (await writeClipboardText(url))
|
|
567
|
+
toast.success(t("agentChat.history.linkCopied"));
|
|
568
|
+
else toast.error(t("agentChat.history.copyLinkFailed"));
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
const mapItem = (
|
|
572
|
+
row: ChatThreadListRow | OwnDraftRow,
|
|
573
|
+
section: OwnershipChatHistorySection,
|
|
574
|
+
) => {
|
|
575
|
+
const override = overrides.get(row.id);
|
|
576
|
+
const title = projectedIntent(override?.title);
|
|
577
|
+
const pin = projectedIntent(override?.pinned);
|
|
578
|
+
const effectiveRow =
|
|
579
|
+
title || pin
|
|
580
|
+
? {
|
|
581
|
+
...row,
|
|
582
|
+
...(title === undefined ? {} : { title: title.value }),
|
|
583
|
+
...(pin === undefined
|
|
584
|
+
? {}
|
|
585
|
+
: {
|
|
586
|
+
pinnedAt: pin.value
|
|
587
|
+
? (("pinnedAt" in row ? row.pinnedAt : null) ?? Date.now())
|
|
588
|
+
: null,
|
|
589
|
+
}),
|
|
590
|
+
}
|
|
591
|
+
: row;
|
|
592
|
+
const mapped =
|
|
593
|
+
"accessBasis" in effectiveRow
|
|
594
|
+
? chatThreadToHistoryItem(effectiveRow as ChatThreadListRow, {
|
|
595
|
+
t,
|
|
596
|
+
activeId,
|
|
597
|
+
locale,
|
|
598
|
+
})
|
|
599
|
+
: ownDraftToHistoryItem(effectiveRow, { t, activeId, locale });
|
|
600
|
+
const item = {
|
|
601
|
+
...mapped,
|
|
602
|
+
...(pin === undefined ? {} : { pinned: pin.value }),
|
|
603
|
+
};
|
|
604
|
+
const decorated = decorateItem?.(item, effectiveRow, { section }) ?? item;
|
|
605
|
+
return section === "shared"
|
|
606
|
+
? { ...decorated, pinned: false, readOnly: true }
|
|
607
|
+
: isPersistedOwner(row)
|
|
608
|
+
? decorated
|
|
609
|
+
: { ...decorated, hideActions: true };
|
|
610
|
+
};
|
|
611
|
+
const visibleMine = mineRows.filter(
|
|
612
|
+
(row) => !projectedIntent(overrides.get(row.id)?.hidden)?.value,
|
|
613
|
+
);
|
|
614
|
+
const pinnedRows = pinned
|
|
615
|
+
? visibleMine.filter(
|
|
616
|
+
(row) =>
|
|
617
|
+
projectedIntent(overrides.get(row.id)?.pinned)?.value ??
|
|
618
|
+
row.pinnedAt != null,
|
|
619
|
+
)
|
|
620
|
+
: [];
|
|
621
|
+
const pinnedIds = new Set(pinnedRows.map((row) => row.id));
|
|
622
|
+
const mineItems = [
|
|
623
|
+
...drafts
|
|
624
|
+
.filter((row) => !projectedIntent(overrides.get(row.id)?.hidden)?.value)
|
|
625
|
+
.filter(
|
|
626
|
+
(row) =>
|
|
627
|
+
(
|
|
628
|
+
projectedIntent(overrides.get(row.id)?.title)?.value ??
|
|
629
|
+
row.title ??
|
|
630
|
+
""
|
|
631
|
+
).includes(normalizedQuery) ||
|
|
632
|
+
(row.preview ?? "").includes(normalizedQuery),
|
|
633
|
+
)
|
|
634
|
+
.map((row) => mapItem(row, "mine")),
|
|
635
|
+
...visibleMine
|
|
636
|
+
.filter((row) => !pinnedIds.has(row.id))
|
|
637
|
+
.map((row) => mapItem(row, "mine")),
|
|
638
|
+
];
|
|
639
|
+
const sectionState = (list: typeof mine) => ({
|
|
640
|
+
loading: enabled && list.loading,
|
|
641
|
+
error: list.error
|
|
642
|
+
? t(
|
|
643
|
+
list.threads.length
|
|
644
|
+
? "agentChat.history.loadMoreFailed"
|
|
645
|
+
: "agentChat.history.loadFailed",
|
|
646
|
+
)
|
|
647
|
+
: undefined,
|
|
648
|
+
onRetry: refresh,
|
|
649
|
+
hasMore: enabled && list.hasMore,
|
|
650
|
+
loadingMore: list.loadingMore,
|
|
651
|
+
onLoadMore: list.loadMore,
|
|
652
|
+
});
|
|
653
|
+
const sections: ChatHistoryRailSection[] = [];
|
|
654
|
+
if (pinnedRows.length)
|
|
655
|
+
sections.push({
|
|
656
|
+
id: "pinned",
|
|
657
|
+
label:
|
|
658
|
+
typeof pinned === "object"
|
|
659
|
+
? (pinned.label ?? t("agentChat.history.pinned"))
|
|
660
|
+
: t("agentChat.history.pinned"),
|
|
661
|
+
items: pinnedRows.map((row) => mapItem(row, "pinned")),
|
|
662
|
+
previewCount: Math.max(1, pinnedRows.length),
|
|
663
|
+
});
|
|
664
|
+
sections.push({
|
|
665
|
+
id: "mine",
|
|
666
|
+
label: t("agentChat.history.mine"),
|
|
667
|
+
items: mineItems,
|
|
668
|
+
previewCount: minePreviewCount,
|
|
669
|
+
...sectionState(mine),
|
|
670
|
+
emptyLabel:
|
|
671
|
+
pinnedRows.length || mine.hasMore
|
|
672
|
+
? undefined
|
|
673
|
+
: t("agentChat.history.emptyMine"),
|
|
674
|
+
});
|
|
675
|
+
if (sharedRows.length || shared.error)
|
|
676
|
+
sections.push({
|
|
677
|
+
id: "shared",
|
|
678
|
+
label: t("agentChat.history.sharedWithYou"),
|
|
679
|
+
items: sharedRows.map((row) => mapItem(row, "shared")),
|
|
680
|
+
previewCount: sharedPreviewCount,
|
|
681
|
+
...sectionState(shared),
|
|
682
|
+
emptyLabel: t("agentChat.history.emptyShared"),
|
|
683
|
+
});
|
|
684
|
+
return {
|
|
685
|
+
sections,
|
|
686
|
+
railLabels: {
|
|
687
|
+
sections: {
|
|
688
|
+
showAll: t("agentChat.history.showAll"),
|
|
689
|
+
showLess: t("agentChat.history.showLess"),
|
|
690
|
+
loadMore: t("agentChat.history.loadMore"),
|
|
691
|
+
loadingMore: t("agentChat.history.loadingMore"),
|
|
692
|
+
retry: t("agentChat.history.retry"),
|
|
693
|
+
},
|
|
694
|
+
},
|
|
695
|
+
listProps,
|
|
696
|
+
mineRows,
|
|
697
|
+
sharedRows,
|
|
698
|
+
loading:
|
|
699
|
+
enabled &&
|
|
700
|
+
mine.loading &&
|
|
701
|
+
shared.loading &&
|
|
702
|
+
mineItems.length === 0 &&
|
|
703
|
+
pinnedRows.length === 0 &&
|
|
704
|
+
sharedRows.length === 0,
|
|
705
|
+
error: mine.error ?? shared.error,
|
|
706
|
+
refresh,
|
|
707
|
+
findMine,
|
|
708
|
+
};
|
|
709
|
+
}
|
|
@@ -766,6 +766,9 @@ const messages: ToolkitAgentChatTranslation = {
|
|
|
766
766
|
"history.ownedBy": "المالك: {{name}}",
|
|
767
767
|
"history.accessDirect": "تمت مشاركتها معك",
|
|
768
768
|
"history.accessOrganization": "تمت مشاركتها مع مؤسستك",
|
|
769
|
+
"history.copyLink": "نسخ الرابط",
|
|
770
|
+
"history.linkCopied": "تم نسخ الرابط",
|
|
771
|
+
"history.copyLinkFailed": "تعذّر نسخ الرابط",
|
|
769
772
|
"integrations.availableSection": "عمليات التكامل المتاحة",
|
|
770
773
|
"integrations.connectedSection": "متصل",
|
|
771
774
|
"integrations.goToApiKeys": "الانتقال إلى مفاتيح API",
|