@itechchoice/prime-chatkit 0.1.0-alpha.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/dist/index.js +10017 -0
- package/dist/style.css +1 -0
- package/dist/types/adapters/bff/client.d.ts +189 -0
- package/dist/types/adapters/bff/controller.d.ts +70 -0
- package/dist/types/components/ui/agent-trail-clean.d.ts +63 -0
- package/dist/types/components/ui/ai-answer-clean.d.ts +76 -0
- package/dist/types/components/ui/approval-card-clean.d.ts +54 -0
- package/dist/types/components/ui/button-clean.d.ts +13 -0
- package/dist/types/components/ui/chat-composer-clean.d.ts +115 -0
- package/dist/types/components/ui/collaboration-stream-clean.d.ts +98 -0
- package/dist/types/components/ui/command-menu-clean.d.ts +57 -0
- package/dist/types/components/ui/decision-card-clean.d.ts +87 -0
- package/dist/types/components/ui/dropzone-clean.d.ts +70 -0
- package/dist/types/components/ui/tool-call-card-clean.d.ts +76 -0
- package/dist/types/core/history.d.ts +3 -0
- package/dist/types/core/run.d.ts +34 -0
- package/dist/types/core/scope.d.ts +16 -0
- package/dist/types/core/sse.d.ts +12 -0
- package/dist/types/core/suspension.d.ts +83 -0
- package/dist/types/core/tools.d.ts +15 -0
- package/dist/types/core/types.d.ts +152 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/layout/DockShell.d.ts +19 -0
- package/dist/types/layout/constants.d.ts +22 -0
- package/dist/types/layout/index.d.ts +3 -0
- package/dist/types/layout/useLayout.d.ts +52 -0
- package/dist/types/provider/PrimeViaChat.d.ts +2 -0
- package/dist/types/provider/PrimeViaChatProvider.d.ts +2 -0
- package/dist/types/provider/PrimeViaChatShell.d.ts +5 -0
- package/dist/types/provider/config.d.ts +92 -0
- package/dist/types/provider/context.d.ts +53 -0
- package/dist/types/provider/hooks.d.ts +82 -0
- package/dist/types/ui/HistoryPanel.d.ts +11 -0
- package/dist/types/ui/blocks/BlocksPanel.d.ts +70 -0
- package/dist/types/ui/blocks/Process.d.ts +7 -0
- package/dist/types/ui/blocks/Questions.d.ts +25 -0
- package/dist/types/ui/blocks/SentAttachments.d.ts +11 -0
- package/dist/types/ui/blocks/useAttachmentDownload.d.ts +9 -0
- package/dist/types/ui/blocks/useAttachments.d.ts +15 -0
- package/dist/types/ui/blocks/useFollowLatest.d.ts +20 -0
- package/dist/types/ui/history.d.ts +10 -0
- package/dist/types/ui/i18n.d.ts +203 -0
- package/dist/types/ui/start-icons.d.ts +2 -0
- package/dist/types/ui/thread.d.ts +71 -0
- package/package.json +52 -0
package/dist/style.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.abc-prime-dock{position:fixed;right:1rem;bottom:1rem;top:auto;left:auto;width:min(720px,94vw);height:calc(100vh - var(--abc-prime-header-offset, var(--chatkit-header-offset, 0px)) - 16px);z-index:60;pointer-events:none;transition:width .22s ease,right .22s ease,bottom .22s ease,transform .22s ease;visibility:hidden}.abc-prime-dock--open{pointer-events:auto;visibility:visible}.abc-prime-dock--minimized{pointer-events:none;visibility:visible}.abc-prime-dock--split{inset:0 0 0 auto;width:var(--abc-prime-split-width, var(--chatkit-split-width, 50vw));min-width:var(--abc-prime-split-min-width, var(--chatkit-split-min-width, 640px));height:100vh;border-left:1px solid var(--border-input, rgba(15, 23, 42, .08))}body.chatkit-resizing .abc-prime-dock,body.chatkit-dragging .abc-prime-dock,body.chatkit-dock-resizing .abc-prime-dock{transition:none}.abc-prime-dock__resize-handle{position:absolute;top:0;bottom:0;left:-12px;width:24px;display:flex;align-items:center;justify-content:center;cursor:col-resize;pointer-events:auto;touch-action:none;-webkit-user-select:none;user-select:none;z-index:2}.abc-prime-dock__panel{display:flex;flex-direction:column;gap:0;border:1px solid var(--border-input, rgba(15, 23, 42, .08));border-radius:1.25rem;background:transparent;box-shadow:0 25px 50px #0f172a2e;padding:0;overflow:hidden;transform:translateY(20px);opacity:0;pointer-events:auto;transition:opacity .18s ease,transform .26s cubic-bezier(.2,.8,.2,1);height:100%}.abc-prime-dock--open .abc-prime-dock__panel{opacity:1;transform:translateY(0)}.abc-prime-dock--split .abc-prime-dock__panel{transform:translate(32px);border-radius:0}.abc-prime-dock--open.abc-prime-dock--split .abc-prime-dock__panel{transform:translate(0)}.abc-prime-dock--minimized .abc-prime-dock__panel{opacity:0;transform:scale(.06) translate(12px,12px);pointer-events:none}.abc-prime-dock__minimized{position:fixed;right:1rem;bottom:1rem;width:48px;height:48px;border-radius:999px;background:rgb(var(--color-theme-blue, 34 99 248));color:#fff;display:inline-flex;align-items:center;justify-content:center;box-shadow:0 12px 24px #2263f847;transform:scale(.6);opacity:0;pointer-events:none;transition:transform .36s cubic-bezier(.18,1.35,.32,1),opacity .32s ease}.abc-prime-dock--minimized .abc-prime-dock__minimized{opacity:1;transform:scale(1);pointer-events:auto}.abc-prime-dock__header{cursor:default}.abc-prime-dock--dock-interactive:not(.abc-prime-dock--split) .abc-prime-dock__header{cursor:grab;touch-action:none}.abc-prime-dock--dragging:not(.abc-prime-dock--split) .abc-prime-dock__header{cursor:grabbing}.abc-prime-dock__resize-corner{position:absolute;right:.75rem;bottom:.75rem;width:18px;height:18px;border:0;background:transparent;cursor:nwse-resize;z-index:3}@media(max-width:640px){.abc-prime-dock{right:.75rem;left:.75rem;width:auto;bottom:.75rem}}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import type { ChatScope } from "../../core/scope";
|
|
2
|
+
import type { SuspensionIdentity } from "../../core/suspension";
|
|
3
|
+
import type { StreamEvent } from "../../core/types";
|
|
4
|
+
export type BffClient = ReturnType<typeof createBffClient>;
|
|
5
|
+
export type BffRequestConfig = {
|
|
6
|
+
method: "get" | "post" | "put" | "delete";
|
|
7
|
+
url: string;
|
|
8
|
+
params?: Record<string, unknown>;
|
|
9
|
+
data?: unknown;
|
|
10
|
+
headers?: Record<string, string>;
|
|
11
|
+
signal?: AbortSignal;
|
|
12
|
+
showLoading: false;
|
|
13
|
+
onUploadProgress?: (event: {
|
|
14
|
+
loaded: number;
|
|
15
|
+
total?: number;
|
|
16
|
+
}) => void;
|
|
17
|
+
};
|
|
18
|
+
export type BffHttp = {
|
|
19
|
+
request: (config: BffRequestConfig) => Promise<unknown>;
|
|
20
|
+
buildStreamHeaders?: (path: string) => Promise<Record<string, string>> | Record<string, string>;
|
|
21
|
+
fetch?: typeof fetch;
|
|
22
|
+
baseUrl?: string;
|
|
23
|
+
streamOrigin?: string;
|
|
24
|
+
};
|
|
25
|
+
export type TaskRequestMetadata = {
|
|
26
|
+
clientId?: string;
|
|
27
|
+
productId?: string;
|
|
28
|
+
pageTraceId?: string;
|
|
29
|
+
modelId?: string;
|
|
30
|
+
capabilities?: string[];
|
|
31
|
+
annotations?: unknown[];
|
|
32
|
+
attachments?: {
|
|
33
|
+
attachmentId: string;
|
|
34
|
+
fileName: string;
|
|
35
|
+
contentType?: string;
|
|
36
|
+
size?: string;
|
|
37
|
+
status: "READY";
|
|
38
|
+
}[];
|
|
39
|
+
autoTitle?: boolean;
|
|
40
|
+
};
|
|
41
|
+
export type TaskDetail = {
|
|
42
|
+
taskId: string;
|
|
43
|
+
status: string;
|
|
44
|
+
sessionId?: string;
|
|
45
|
+
eventWatermark?: string;
|
|
46
|
+
activeSuspension?: unknown;
|
|
47
|
+
runMetadata?: unknown;
|
|
48
|
+
};
|
|
49
|
+
export type SessionListInput = {
|
|
50
|
+
page?: number;
|
|
51
|
+
size?: number;
|
|
52
|
+
keyword?: string;
|
|
53
|
+
};
|
|
54
|
+
export type SessionSummary = {
|
|
55
|
+
id: string;
|
|
56
|
+
title?: string;
|
|
57
|
+
updatedAt?: string;
|
|
58
|
+
createdAt?: string;
|
|
59
|
+
};
|
|
60
|
+
export type SessionList = {
|
|
61
|
+
items: SessionSummary[];
|
|
62
|
+
total?: number;
|
|
63
|
+
};
|
|
64
|
+
export type SessionPageInput = {
|
|
65
|
+
limit?: number;
|
|
66
|
+
before?: string;
|
|
67
|
+
};
|
|
68
|
+
export type SessionPage = {
|
|
69
|
+
id: string;
|
|
70
|
+
title?: string;
|
|
71
|
+
hasMore: boolean;
|
|
72
|
+
records: unknown[];
|
|
73
|
+
};
|
|
74
|
+
export type RenamedSession = {
|
|
75
|
+
id: string;
|
|
76
|
+
title?: string;
|
|
77
|
+
};
|
|
78
|
+
export type ScopeSessionInput = Omit<ChatScope, "pending">;
|
|
79
|
+
export type ProvisioningStatus = {
|
|
80
|
+
ready: boolean;
|
|
81
|
+
overallStatus: string | null;
|
|
82
|
+
lastFailedStep: string | null;
|
|
83
|
+
lastFailedReason: string | null;
|
|
84
|
+
expiresAt: string | null;
|
|
85
|
+
};
|
|
86
|
+
export type SubscribeEnd = {
|
|
87
|
+
kind: "finished";
|
|
88
|
+
} | {
|
|
89
|
+
kind: "suspended";
|
|
90
|
+
} | {
|
|
91
|
+
kind: "aborted";
|
|
92
|
+
} | {
|
|
93
|
+
kind: "lost";
|
|
94
|
+
status?: number;
|
|
95
|
+
message?: string;
|
|
96
|
+
};
|
|
97
|
+
export declare class BffContractError extends Error {
|
|
98
|
+
readonly code: string;
|
|
99
|
+
readonly status?: number | undefined;
|
|
100
|
+
constructor(code: string, status?: number | undefined, message?: string);
|
|
101
|
+
}
|
|
102
|
+
export type AttachmentLimits = {
|
|
103
|
+
allowedExtensions: string[];
|
|
104
|
+
maxSizeBytes?: number;
|
|
105
|
+
};
|
|
106
|
+
export type UploadedAttachment = {
|
|
107
|
+
id: string;
|
|
108
|
+
name: string;
|
|
109
|
+
mimeType?: string;
|
|
110
|
+
size?: string;
|
|
111
|
+
status?: string;
|
|
112
|
+
ready: boolean;
|
|
113
|
+
};
|
|
114
|
+
export type AttachmentUrls = {
|
|
115
|
+
url?: string;
|
|
116
|
+
originalUrl?: string;
|
|
117
|
+
contentType?: string;
|
|
118
|
+
originalContentType?: string;
|
|
119
|
+
expiresIn?: number;
|
|
120
|
+
};
|
|
121
|
+
export declare function checkAttachment(file: {
|
|
122
|
+
name: string;
|
|
123
|
+
size: number;
|
|
124
|
+
}, limits: AttachmentLimits): "ok" | "extension" | "size";
|
|
125
|
+
export declare function createBffClient(http: BffHttp): {
|
|
126
|
+
getProvisioning(): Promise<ProvisioningStatus>;
|
|
127
|
+
triggerProvisioning(): Promise<ProvisioningStatus>;
|
|
128
|
+
listSessions(input?: SessionListInput): Promise<SessionList>;
|
|
129
|
+
getSessionPage(sessionId: string, input?: SessionPageInput): Promise<SessionPage>;
|
|
130
|
+
renameSession(sessionId: string, title: string): Promise<RenamedSession>;
|
|
131
|
+
deleteSession(sessionId: string): Promise<boolean>;
|
|
132
|
+
getScopeSession(input: ScopeSessionInput): Promise<string | null>;
|
|
133
|
+
createSession(input?: {
|
|
134
|
+
title?: string;
|
|
135
|
+
signal?: AbortSignal;
|
|
136
|
+
}): Promise<{
|
|
137
|
+
sessionId: string;
|
|
138
|
+
}>;
|
|
139
|
+
getAttachmentLimits(): Promise<AttachmentLimits>;
|
|
140
|
+
checkAttachment: typeof checkAttachment;
|
|
141
|
+
uploadAttachment(input: {
|
|
142
|
+
sessionId: string;
|
|
143
|
+
file: Blob & {
|
|
144
|
+
name?: string;
|
|
145
|
+
};
|
|
146
|
+
onProgress?: (p: number) => void;
|
|
147
|
+
signal?: AbortSignal;
|
|
148
|
+
}): Promise<UploadedAttachment>;
|
|
149
|
+
deleteAttachment(sessionId: string, attachmentId: string): Promise<boolean>;
|
|
150
|
+
getAttachmentUrls(attachmentId: string): Promise<AttachmentUrls>;
|
|
151
|
+
submitFeedback(input: {
|
|
152
|
+
taskId: string;
|
|
153
|
+
messageId: string;
|
|
154
|
+
rating: 1 | -1;
|
|
155
|
+
labels?: string[];
|
|
156
|
+
comment?: string;
|
|
157
|
+
}): Promise<{
|
|
158
|
+
feedbackId?: string;
|
|
159
|
+
}>;
|
|
160
|
+
createTask(input: {
|
|
161
|
+
sessionId?: string;
|
|
162
|
+
message: string;
|
|
163
|
+
requestMetadata?: TaskRequestMetadata;
|
|
164
|
+
signal?: AbortSignal;
|
|
165
|
+
}): Promise<{
|
|
166
|
+
taskId: string;
|
|
167
|
+
sessionId?: string;
|
|
168
|
+
status?: string;
|
|
169
|
+
}>;
|
|
170
|
+
cancelTask(taskId: string, reason?: string): Promise<boolean>;
|
|
171
|
+
resumeTask(taskId: string, input: {
|
|
172
|
+
suspensionId: string;
|
|
173
|
+
action: "APPROVE" | "REJECT" | "SUBMIT" | "CANCEL";
|
|
174
|
+
payload: Record<string, unknown>;
|
|
175
|
+
identity?: SuspensionIdentity;
|
|
176
|
+
signal?: AbortSignal;
|
|
177
|
+
}): Promise<{
|
|
178
|
+
status?: string;
|
|
179
|
+
resolution?: string;
|
|
180
|
+
}>;
|
|
181
|
+
getTask(taskId: string): Promise<TaskDetail>;
|
|
182
|
+
subscribeTaskEvents(input: {
|
|
183
|
+
taskId: string;
|
|
184
|
+
cursor: () => string | undefined;
|
|
185
|
+
onEvent: (ev: StreamEvent) => void;
|
|
186
|
+
signal?: AbortSignal;
|
|
187
|
+
delays?: number[];
|
|
188
|
+
}): Promise<SubscribeEnd>;
|
|
189
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { type ChatScope } from "../../core/scope";
|
|
2
|
+
import { type Suspension, type SuspensionAnswer } from "../../core/suspension";
|
|
3
|
+
import type { ChatMessage } from "../../core/types";
|
|
4
|
+
import { type BffClient, type ProvisioningStatus, type SessionSummary, type TaskRequestMetadata, type UploadedAttachment } from "./client";
|
|
5
|
+
export type { ChatScope } from "../../core/scope";
|
|
6
|
+
export declare const HOLD_SESSION_ON_LINK_MS = 10000;
|
|
7
|
+
export type ProvisioningState = ProvisioningStatus & {
|
|
8
|
+
checked: boolean;
|
|
9
|
+
triggering: boolean;
|
|
10
|
+
error?: {
|
|
11
|
+
code: "provisioning-check-failed" | "provisioning-trigger-failed";
|
|
12
|
+
status?: number;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export type ControllerState = {
|
|
16
|
+
sessionId?: string;
|
|
17
|
+
title?: string;
|
|
18
|
+
messages: ChatMessage[];
|
|
19
|
+
phase: "idle" | "loading" | "running" | "stopping";
|
|
20
|
+
connection: "online" | "lost";
|
|
21
|
+
hasMore: boolean;
|
|
22
|
+
loadingOlder: boolean;
|
|
23
|
+
error?: {
|
|
24
|
+
code: string;
|
|
25
|
+
status?: number;
|
|
26
|
+
};
|
|
27
|
+
suspension?: Suspension;
|
|
28
|
+
provisioning?: ProvisioningState;
|
|
29
|
+
sessions?: {
|
|
30
|
+
items: SessionSummary[];
|
|
31
|
+
loading: boolean;
|
|
32
|
+
error?: {
|
|
33
|
+
code: "sessions-failed" | "rename-failed" | "delete-failed";
|
|
34
|
+
status?: number;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
export declare function createChatController(deps: {
|
|
39
|
+
client: BffClient;
|
|
40
|
+
stopPoll?: {
|
|
41
|
+
intervalMs: number;
|
|
42
|
+
timeoutMs: number;
|
|
43
|
+
};
|
|
44
|
+
pageSize?: number;
|
|
45
|
+
getTraceId?: () => string | undefined;
|
|
46
|
+
provisioning?: boolean;
|
|
47
|
+
}): {
|
|
48
|
+
getState(): ControllerState;
|
|
49
|
+
subscribe(listener: () => void): () => void;
|
|
50
|
+
setScope(scope: ChatScope | null): Promise<void>;
|
|
51
|
+
keepSessionOnNextScopeChange(ttlMs?: number): void;
|
|
52
|
+
provision(): Promise<void>;
|
|
53
|
+
openSession(sessionId: string): Promise<void>;
|
|
54
|
+
loadSessions(): Promise<void>;
|
|
55
|
+
renameSession(id: string, title: string): Promise<void>;
|
|
56
|
+
deleteSession(id: string): Promise<void>;
|
|
57
|
+
newChat(): void;
|
|
58
|
+
loadOlder(): Promise<void>;
|
|
59
|
+
send(text: string, opts?: {
|
|
60
|
+
attachments?: UploadedAttachment[];
|
|
61
|
+
requestMetadata?: Omit<TaskRequestMetadata, "attachments">;
|
|
62
|
+
}): Promise<void>;
|
|
63
|
+
stop(): Promise<void>;
|
|
64
|
+
answer(a: SuspensionAnswer): Promise<void>;
|
|
65
|
+
cancelSuspension(): Promise<void>;
|
|
66
|
+
upload(file: Blob & {
|
|
67
|
+
name?: string;
|
|
68
|
+
}, onProgress?: (p: number) => void, signal?: AbortSignal): Promise<UploadedAttachment>;
|
|
69
|
+
dispose(): void;
|
|
70
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export type TrailStepState = "done" | "running" | "pending" | "waiting" | "failed" | "stopped";
|
|
2
|
+
export type TrailSubstepState = "done" | "running" | "pending";
|
|
3
|
+
export type TrailSubstep = {
|
|
4
|
+
id?: string;
|
|
5
|
+
title: string;
|
|
6
|
+
/** done by default */
|
|
7
|
+
state?: TrailSubstepState;
|
|
8
|
+
/** A short fact on the right – a file, "+18 −3", "182/214" */
|
|
9
|
+
detail?: string;
|
|
10
|
+
};
|
|
11
|
+
export type TrailStep = {
|
|
12
|
+
id: string;
|
|
13
|
+
title: string;
|
|
14
|
+
state: TrailStepState;
|
|
15
|
+
/** How long it took – ms as a number ("12s", "1m 4s"), or your own text */
|
|
16
|
+
duration?: number | string;
|
|
17
|
+
/** What it is doing right now, on the right of a running step – "Testing" */
|
|
18
|
+
status?: string;
|
|
19
|
+
/** When a running step started (ms, Date.now()) – shows a live timer next to its status */
|
|
20
|
+
startedAt?: number;
|
|
21
|
+
/** Needs a person's approval before it runs – a dashed ring and "Approval" while it waits its turn */
|
|
22
|
+
gate?: boolean;
|
|
23
|
+
/** What it does inside the step – branches off the trail under it */
|
|
24
|
+
substeps?: TrailSubstep[];
|
|
25
|
+
/** Select this step to show details outside the fixed-height trail. */
|
|
26
|
+
selectable?: boolean;
|
|
27
|
+
};
|
|
28
|
+
export type AgentTrailLabels = {
|
|
29
|
+
title: string;
|
|
30
|
+
running: string;
|
|
31
|
+
approval: string;
|
|
32
|
+
waiting: string;
|
|
33
|
+
failed: string;
|
|
34
|
+
done: string;
|
|
35
|
+
pending: string;
|
|
36
|
+
/** No steps at all */
|
|
37
|
+
empty: string;
|
|
38
|
+
/** A step or sub-step without a title */
|
|
39
|
+
untitled: string;
|
|
40
|
+
/** "+35 earlier" / "+3 more" over and under a long list of sub-steps */
|
|
41
|
+
earlier: string;
|
|
42
|
+
more: string;
|
|
43
|
+
fewer: string;
|
|
44
|
+
stopped: string;
|
|
45
|
+
count: (done: number, total: number) => string;
|
|
46
|
+
duration: (ms: number) => string;
|
|
47
|
+
};
|
|
48
|
+
export type AgentTrailProps = {
|
|
49
|
+
steps: TrailStep[];
|
|
50
|
+
/** The task, in the header – leave it out for no header */
|
|
51
|
+
title?: string;
|
|
52
|
+
/** Which steps show their sub-steps – by default only the running one */
|
|
53
|
+
expanded?: string[];
|
|
54
|
+
onExpandedChange?: (ids: string[]) => void;
|
|
55
|
+
labels?: Partial<AgentTrailLabels>;
|
|
56
|
+
className?: string;
|
|
57
|
+
selected?: string | null;
|
|
58
|
+
onSelect?: (id: string) => void;
|
|
59
|
+
detailId?: string;
|
|
60
|
+
};
|
|
61
|
+
/** 12s, 1m 4s, 1h 2m – a string is shown as it is, anything broken as nothing */
|
|
62
|
+
export declare function formatDuration(d: number | string | undefined): string;
|
|
63
|
+
export declare function AgentTrail({ steps, title, expanded: expandedProp, onExpandedChange, labels: labelsProp, className, selected, onSelect, detailId }: AgentTrailProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { MouseEvent } from "react";
|
|
3
|
+
export type AnswerSource = {
|
|
4
|
+
/** Headline of the page, message or document */
|
|
5
|
+
title: string;
|
|
6
|
+
/** Short name shown on the citation chip, e.g. "Notion" */
|
|
7
|
+
name: string;
|
|
8
|
+
/** Opens in a new tab */
|
|
9
|
+
href?: string;
|
|
10
|
+
/** A favicon or logo, ideally square */
|
|
11
|
+
icon?: ReactNode;
|
|
12
|
+
/** The passage the answer relies on – shown in the preview */
|
|
13
|
+
snippet?: string;
|
|
14
|
+
};
|
|
15
|
+
export type AIAnswerProps = {
|
|
16
|
+
labels?: Partial<AIAnswerLabels>;
|
|
17
|
+
stopped?: boolean;
|
|
18
|
+
stoppable?: boolean;
|
|
19
|
+
/** Milliseconds; null hides elapsed time, undefined keeps the internal timer. */
|
|
20
|
+
duration?: number | null;
|
|
21
|
+
actions?: ("copy" | "regenerate" | "feedback")[];
|
|
22
|
+
avatar?: string;
|
|
23
|
+
onLink?: (href: string, event: MouseEvent<HTMLAnchorElement>) => void;
|
|
24
|
+
/** The question above the answer */
|
|
25
|
+
question?: string;
|
|
26
|
+
sources: AnswerSource[];
|
|
27
|
+
/** The answer text – may grow while `streaming` is true */
|
|
28
|
+
answer: string;
|
|
29
|
+
/** Render GFM and CJK-friendly Markdown immediately, without word animation. */
|
|
30
|
+
markdown?: boolean;
|
|
31
|
+
/** More text is still coming from your model, keep the cursor going */
|
|
32
|
+
streaming?: boolean;
|
|
33
|
+
/** Stream the text in; false shows it at once */
|
|
34
|
+
animate?: boolean;
|
|
35
|
+
/** Words per second while streaming in */
|
|
36
|
+
speed?: number;
|
|
37
|
+
followUps?: string[];
|
|
38
|
+
onFollowUp?: (question: string) => void;
|
|
39
|
+
onRegenerate?: () => void;
|
|
40
|
+
onStop?: () => void;
|
|
41
|
+
onFeedback?: (value: "up" | "down", reason?: string) => void;
|
|
42
|
+
/** Reasons offered after a thumbs down */
|
|
43
|
+
feedbackReasons?: string[];
|
|
44
|
+
onCopy?: (text: string) => void;
|
|
45
|
+
/** Its own white card – leave it off where the answer already sits on a surface (a thread, panel or sheet) */
|
|
46
|
+
framed?: boolean;
|
|
47
|
+
className?: string;
|
|
48
|
+
};
|
|
49
|
+
export type AIAnswerLabels = {
|
|
50
|
+
/** Counts preserve the component's existing formatting. */
|
|
51
|
+
reading: (count: string) => string;
|
|
52
|
+
writing: string;
|
|
53
|
+
answer: string;
|
|
54
|
+
stop: string;
|
|
55
|
+
stopped: string;
|
|
56
|
+
stoppedBeforeAnswering: string;
|
|
57
|
+
copyAnswer: string;
|
|
58
|
+
copied: string;
|
|
59
|
+
regenerate: string;
|
|
60
|
+
goodAnswer: string;
|
|
61
|
+
badAnswer: string;
|
|
62
|
+
thanksFeedback: string;
|
|
63
|
+
feedbackPrompt: string;
|
|
64
|
+
feedbackReasons: string[];
|
|
65
|
+
related: string;
|
|
66
|
+
sources: string;
|
|
67
|
+
clipboardSources: string;
|
|
68
|
+
source: (names: string) => string;
|
|
69
|
+
more: (count: string) => string;
|
|
70
|
+
moreLabel: string;
|
|
71
|
+
/** Includes any separator before the formatted duration. */
|
|
72
|
+
answeredIn: string;
|
|
73
|
+
formatDuration: (seconds: number) => string;
|
|
74
|
+
};
|
|
75
|
+
export declare const defaultAIAnswerLabels: AIAnswerLabels;
|
|
76
|
+
export declare function AIAnswer({ labels, stopped, stoppable, duration, actions, avatar, onLink, question, sources, answer, markdown, streaming, animate, speed, followUps, onFollowUp, onRegenerate, onStop, onFeedback, feedbackReasons, onCopy, framed, className, }: AIAnswerProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
export type ApprovalStatus = "pending" | "approved" | "denied";
|
|
3
|
+
export type ApprovalRisk = "low" | "medium" | "high";
|
|
4
|
+
export type ApprovalDetail = {
|
|
5
|
+
label: string;
|
|
6
|
+
value: ReactNode;
|
|
7
|
+
};
|
|
8
|
+
export type DenyReason = "user" | "timeout";
|
|
9
|
+
export type ApprovalCardProps = {
|
|
10
|
+
/** The action, e.g. "Send campaign email" */
|
|
11
|
+
title: string;
|
|
12
|
+
/** One line of context below the title */
|
|
13
|
+
description?: ReactNode;
|
|
14
|
+
/** Tinted badge in the header; leave out to hide it */
|
|
15
|
+
risk?: ApprovalRisk;
|
|
16
|
+
/** Icon in the header tile – defaults to a small shield */
|
|
17
|
+
icon?: ReactNode;
|
|
18
|
+
/** Key-value rows in the preview, e.g. To, Subject, Scheduled */
|
|
19
|
+
details?: ApprovalDetail[];
|
|
20
|
+
/** Anything to show above the details, e.g. a recipient list – children work too */
|
|
21
|
+
preview?: ReactNode;
|
|
22
|
+
children?: ReactNode;
|
|
23
|
+
/** Controlled status */
|
|
24
|
+
status?: ApprovalStatus;
|
|
25
|
+
/** Starting status when uncontrolled */
|
|
26
|
+
defaultStatus?: ApprovalStatus;
|
|
27
|
+
/** Return a promise to show a spinner and lock the card until it settles; a rejection keeps it pending */
|
|
28
|
+
onApprove?: (decision: {
|
|
29
|
+
always: boolean;
|
|
30
|
+
}) => void | Promise<unknown>;
|
|
31
|
+
onDeny?: (decision: {
|
|
32
|
+
reason: DenyReason;
|
|
33
|
+
}) => void;
|
|
34
|
+
/** Shows an "Edit" button */
|
|
35
|
+
onEdit?: () => void;
|
|
36
|
+
/** Seconds until the request expires and is denied with reason "timeout" */
|
|
37
|
+
expiresIn?: number;
|
|
38
|
+
/** Called when the countdown runs out (onDeny is called too) */
|
|
39
|
+
onExpire?: () => void;
|
|
40
|
+
/** Show the "Always allow this action" checkbox */
|
|
41
|
+
allowAlways?: boolean;
|
|
42
|
+
alwaysLabel?: string;
|
|
43
|
+
approveLabel?: string;
|
|
44
|
+
denyLabel?: string;
|
|
45
|
+
editLabel?: string;
|
|
46
|
+
/** Show ⌘↵ / Esc hints on the buttons (the shortcuts work either way) */
|
|
47
|
+
shortcuts?: boolean;
|
|
48
|
+
/** Small label on the gray tray above the card, e.g. "Step 4 · gmail.send" */
|
|
49
|
+
label?: ReactNode;
|
|
50
|
+
/** Where the buttons sit: on the gray tray below the card (default) or inside the white card */
|
|
51
|
+
actions?: "tray" | "card";
|
|
52
|
+
className?: string;
|
|
53
|
+
};
|
|
54
|
+
export declare function ApprovalCard({ title, description, risk, icon, details, preview, children, status: statusProp, defaultStatus, onApprove, onDeny, onEdit, expiresIn, onExpire, allowAlways, alwaysLabel, approveLabel, denyLabel, editLabel, shortcuts, label, actions, className, }: ApprovalCardProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type ComponentPropsWithRef, type ReactNode } from "react";
|
|
2
|
+
export type ButtonProps = ComponentPropsWithRef<"button"> & {
|
|
3
|
+
/** primary: a dark chip · secondary: white with a hairline shadow · ghost: text only · destructive: a light red fill, for deleting */
|
|
4
|
+
variant?: "primary" | "secondary" | "ghost" | "destructive";
|
|
5
|
+
size?: "sm" | "md" | "lg";
|
|
6
|
+
/** Shows a shimmer over the label and blocks clicks */
|
|
7
|
+
loading?: boolean;
|
|
8
|
+
/** Icon before the label, e.g. an inline SVG */
|
|
9
|
+
icon?: ReactNode;
|
|
10
|
+
/** Icon after the label */
|
|
11
|
+
iconRight?: ReactNode;
|
|
12
|
+
};
|
|
13
|
+
export declare function Button({ variant, size, loading, icon, iconRight, children, className, disabled, onClick, onPointerEnter, type, ref, ...rest }: ButtonProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { type ComponentType, type ReactNode } from "react";
|
|
2
|
+
/** An app under "Connect apps" – its brand mark shows in the row and in the menu */
|
|
3
|
+
export type ChatApp = {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
Logo: ComponentType;
|
|
7
|
+
};
|
|
8
|
+
export type ChatModel = {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
/** A line under the name in the picker – leave it out for names alone */
|
|
12
|
+
description?: string;
|
|
13
|
+
Logo?: ComponentType;
|
|
14
|
+
};
|
|
15
|
+
/** How the agent's actions get approved: ask first, approve the safe ones by itself, or never ask */
|
|
16
|
+
export type ApprovalMode = "ask" | "auto" | "full";
|
|
17
|
+
export declare const defaultChatComposerLabels: {
|
|
18
|
+
placeholder: string;
|
|
19
|
+
requestApproval: string;
|
|
20
|
+
requestApprovalDescription: string;
|
|
21
|
+
approveForMe: string;
|
|
22
|
+
approveForMeDescription: string;
|
|
23
|
+
fullAccess: string;
|
|
24
|
+
fullAccessDescription: string;
|
|
25
|
+
add: string;
|
|
26
|
+
files: string;
|
|
27
|
+
attachClaude: string;
|
|
28
|
+
workInFolder: string;
|
|
29
|
+
chooseFolder: string;
|
|
30
|
+
goal: string;
|
|
31
|
+
goalDescription: string;
|
|
32
|
+
planMode: string;
|
|
33
|
+
planOnDescription: string;
|
|
34
|
+
recordSkill: string;
|
|
35
|
+
draw: string;
|
|
36
|
+
drawDescription: string;
|
|
37
|
+
plugins: string;
|
|
38
|
+
documents: string;
|
|
39
|
+
documentsDescription: string;
|
|
40
|
+
pdf: string;
|
|
41
|
+
pdfDescription: string;
|
|
42
|
+
noFolder: string;
|
|
43
|
+
planOff: string;
|
|
44
|
+
planOn: string;
|
|
45
|
+
recording: string;
|
|
46
|
+
recordingAdded: string;
|
|
47
|
+
recordingDiscarded: string;
|
|
48
|
+
messageSent: string;
|
|
49
|
+
composer: string;
|
|
50
|
+
message: string;
|
|
51
|
+
voiceInput: string;
|
|
52
|
+
sendMessage: string;
|
|
53
|
+
discardRecording: string;
|
|
54
|
+
useRecording: string;
|
|
55
|
+
connectApps: string;
|
|
56
|
+
addToChat: string;
|
|
57
|
+
planOffDescription: string;
|
|
58
|
+
approvalQuestion: string;
|
|
59
|
+
learnMore: string;
|
|
60
|
+
selectModel: string;
|
|
61
|
+
apps: string;
|
|
62
|
+
workingIn: (folder: string) => string;
|
|
63
|
+
appConnection: (name: string | undefined, connected: boolean) => string;
|
|
64
|
+
selected: (name: string | undefined) => string;
|
|
65
|
+
connectedCount: (n: number) => string;
|
|
66
|
+
};
|
|
67
|
+
export type ChatComposerLabels = typeof defaultChatComposerLabels;
|
|
68
|
+
export type ChatComposerProps = {
|
|
69
|
+
sendDisabled?: boolean;
|
|
70
|
+
labels?: Partial<ChatComposerLabels>;
|
|
71
|
+
placeholder?: string;
|
|
72
|
+
disabled?: boolean;
|
|
73
|
+
/** Models in the picker; the first one is selected by default */
|
|
74
|
+
models?: ChatModel[];
|
|
75
|
+
/** Demo transcript that appears word by word while recording – replace with live speech-to-text */
|
|
76
|
+
dictation?: string;
|
|
77
|
+
onSend?: (message: string, details: {
|
|
78
|
+
model: string;
|
|
79
|
+
}) => void;
|
|
80
|
+
onModelChange?: (model: ChatModel) => void;
|
|
81
|
+
/** An entry of the plus menu was picked: "files", "claude", "folder", "goal", "plan", "skill", "draw", "documents" or "pdf" */
|
|
82
|
+
onAttach?: (item: string) => void;
|
|
83
|
+
/** Plus-menu row IDs to show, after the tray's folder/apps replacement; omitted, show all. */
|
|
84
|
+
addItems?: string[];
|
|
85
|
+
/** The approval mode to start with; false removes the button and menu. */
|
|
86
|
+
approval?: ApprovalMode | false;
|
|
87
|
+
/** False removes voice input and prevents recording. */
|
|
88
|
+
voice?: boolean;
|
|
89
|
+
onApprovalChange?: (mode: ApprovalMode) => void;
|
|
90
|
+
/** "Learn more" in the approval menu */
|
|
91
|
+
onLearnMore?: () => void;
|
|
92
|
+
/** Folders in the "Work in a folder" picker – an empty list leaves the picker out */
|
|
93
|
+
folders?: string[];
|
|
94
|
+
/** The folder to start in */
|
|
95
|
+
folder?: string;
|
|
96
|
+
/** A folder was picked – null when the picked one was picked again to leave it */
|
|
97
|
+
onFolderChange?: (folder: string | null) => void;
|
|
98
|
+
/** Apps in the "Connect apps" menu; the first three show their marks in the row */
|
|
99
|
+
apps?: ChatApp[];
|
|
100
|
+
/** Ids of the apps that are connected to start with */
|
|
101
|
+
connectedApps?: string[];
|
|
102
|
+
/** An app was connected or disconnected – with the ids of all connected apps */
|
|
103
|
+
onAppsChange?: (connected: string[]) => void;
|
|
104
|
+
/** Your own last row on the gray layer, in place of "Work in a folder" and "Connect apps" */
|
|
105
|
+
foot?: ReactNode;
|
|
106
|
+
/**
|
|
107
|
+
* The gray layer under the writing area with the folder and the apps (default true). Turn it off once a chat has
|
|
108
|
+
* started: the folder is set by then, and the apps move into the plus menu
|
|
109
|
+
*/
|
|
110
|
+
tray?: boolean;
|
|
111
|
+
};
|
|
112
|
+
export declare const defaultFolders: string[];
|
|
113
|
+
export declare const defaultApps: ChatApp[];
|
|
114
|
+
export declare const defaultModels: ChatModel[];
|
|
115
|
+
export declare function ChatComposer({ sendDisabled, placeholder, disabled, labels: labelProp, models, dictation, onSend, onModelChange, onAttach, addItems, voice, approval: firstApproval, onApprovalChange, onLearnMore, folders, folder: firstFolder, onFolderChange, apps, connectedApps, onAppsChange, foot, tray, }: ChatComposerProps): import("react").JSX.Element;
|