@arbidocs/react 0.4.3 → 0.4.4
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/README.md +22 -0
- package/dist/index.cjs +384 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1522 -82
- package/dist/index.d.ts +1522 -82
- package/dist/index.js +363 -21
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -126,3 +126,25 @@ queryClient.invalidateQueries({ queryKey: arbiQueryKeys.documents(workspaceId) }
|
|
|
126
126
|
## Peer dependencies
|
|
127
127
|
|
|
128
128
|
- `react` >= 18
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
## Tasks, agents, skills, contacts and credits
|
|
132
|
+
|
|
133
|
+
Hooks for an "AI workforce" and a messages screen. Writes invalidate through `arbiQueryKeys`, so
|
|
134
|
+
`useTasks`, `useAgents`, `useConfigs` and `useDirectMessages` refresh by themselves.
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
const create = useCreateTask() // mutateAsync(CreateTaskRequest) -> TaskResponse
|
|
138
|
+
const run = useRunTask() // approves a run parked for access (temporary grant), then runs
|
|
139
|
+
const runs = useTaskRuns(taskId) // polls while a run is in flight
|
|
140
|
+
const save = useSaveAgentConfig() // { agentExtId, sections: { Agents: { PERSONA, ... } } }
|
|
141
|
+
const grant = useGrantAgentAccess() // { agentExtId, workspaceId, mode?: { kind: 'standing' | 'temporary' } }
|
|
142
|
+
const contacts = usePendingContacts() // + useAddContacts(), useRemoveContacts()
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Form-to-request mappings (`taskComposerToCreateRequest`, `composePersona`, ...) are in
|
|
146
|
+
`@arbidocs/blocks/agents`. Usage is reported in **credits**, not dollars: use
|
|
147
|
+
`formatCredits(n)`, `creditsToUsd(n)` and the `metered` flag on `useProjectUsage` /
|
|
148
|
+
`useProjectsUsage` (`false` = this deployment does not record usage). `DirectMessages` takes
|
|
149
|
+
`listHeader`, `listLead`, `startByEmail` and `hideOwnContact`. See `docs/design/blocks-package.md`
|
|
150
|
+
("Hooks and mappings a host should not rewrite").
|
package/dist/index.cjs
CHANGED
|
@@ -25,6 +25,23 @@ var React__default = /*#__PURE__*/_interopDefault(React);
|
|
|
25
25
|
var ReactMarkdown__default = /*#__PURE__*/_interopDefault(ReactMarkdown);
|
|
26
26
|
var Cropper__default = /*#__PURE__*/_interopDefault(Cropper);
|
|
27
27
|
|
|
28
|
+
// src/credits.ts
|
|
29
|
+
var DEFAULT_USD_PER_CREDIT = 0.01;
|
|
30
|
+
function formatCredits(credits, options = {}) {
|
|
31
|
+
const { unit = true, locale = "en-US" } = options;
|
|
32
|
+
const whole = Math.round(Number.isFinite(credits) ? credits : 0);
|
|
33
|
+
const digits = whole.toLocaleString(locale);
|
|
34
|
+
return unit ? `${digits} ${whole === 1 ? "credit" : "credits"}` : digits;
|
|
35
|
+
}
|
|
36
|
+
function creditsToUsd(credits, usdPerCredit = DEFAULT_USD_PER_CREDIT) {
|
|
37
|
+
return credits * usdPerCredit;
|
|
38
|
+
}
|
|
39
|
+
function isUsageMetered(usage, subscription) {
|
|
40
|
+
const empty = usage.total_spend === 0 && usage.total_tokens === 0 && usage.total_requests === 0;
|
|
41
|
+
return !(empty && subscription === "dev");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/hooks.ts
|
|
28
45
|
var arbiQueryKeys = {
|
|
29
46
|
workspaces: () => ["arbi", "workspaces"],
|
|
30
47
|
documents: (workspaceId) => ["arbi", "documents", workspaceId],
|
|
@@ -42,7 +59,14 @@ var arbiQueryKeys = {
|
|
|
42
59
|
projects: () => ["arbi", "projects"],
|
|
43
60
|
projectUsage: (projectExtId, monthsBack) => ["arbi", "projectUsage", projectExtId, monthsBack],
|
|
44
61
|
projectInvoices: (projectExtId) => ["arbi", "projectInvoices", projectExtId],
|
|
45
|
-
userUsageToday: () => ["arbi", "userUsageToday"]
|
|
62
|
+
userUsageToday: () => ["arbi", "userUsageToday"],
|
|
63
|
+
contacts: () => ["arbi", "contacts"],
|
|
64
|
+
skills: () => ["arbi", "skills"],
|
|
65
|
+
taskRuns: (taskId) => ["arbi", "taskRuns", taskId],
|
|
66
|
+
/** An agent's pinned config; `undefined` = the library default config. */
|
|
67
|
+
agentConfig: (agentExtId) => ["arbi", "agentConfig", agentExtId ?? "default"],
|
|
68
|
+
agentWorkspaces: (agentExtId) => ["arbi", "agentWorkspaces", agentExtId],
|
|
69
|
+
models: () => ["arbi", "models"]
|
|
46
70
|
};
|
|
47
71
|
function useWorkspaces(options) {
|
|
48
72
|
const arbi = chunk7IOCMCC5_cjs.useArbi();
|
|
@@ -171,15 +195,20 @@ function useProjects(options) {
|
|
|
171
195
|
}
|
|
172
196
|
function useProjectUsage(projectExtId, monthsBack = 0, options) {
|
|
173
197
|
const arbi = chunk7IOCMCC5_cjs.useArbi();
|
|
174
|
-
|
|
198
|
+
const usage = reactQuery.useQuery({
|
|
175
199
|
queryKey: arbiQueryKeys.projectUsage(projectExtId ?? "", monthsBack),
|
|
176
200
|
queryFn: () => arbi.projects.usage(projectExtId, monthsBack),
|
|
177
201
|
enabled: (options?.enabled ?? true) && !!projectExtId && arbi.isLoggedIn
|
|
178
202
|
});
|
|
203
|
+
const projects = useProjects({ enabled: !!projectExtId && (options?.enabled ?? true) });
|
|
204
|
+
const subscription = projects.data?.find((p) => p.external_id === projectExtId)?.subscription;
|
|
205
|
+
const metered = usage.data ? isUsageMetered(usage.data, subscription) : void 0;
|
|
206
|
+
return { ...usage, metered };
|
|
179
207
|
}
|
|
180
208
|
function useProjectsUsage(projectExtIds, monthsBack = 0, options) {
|
|
181
209
|
const arbi = chunk7IOCMCC5_cjs.useArbi();
|
|
182
210
|
const enabled = (options?.enabled ?? true) && arbi.isLoggedIn;
|
|
211
|
+
const projects = useProjects({ enabled: enabled && projectExtIds.length > 0 });
|
|
183
212
|
const results = reactQuery.useQueries({
|
|
184
213
|
queries: projectExtIds.map((id) => ({
|
|
185
214
|
queryKey: arbiQueryKeys.projectUsage(id, monthsBack),
|
|
@@ -187,27 +216,34 @@ function useProjectsUsage(projectExtIds, monthsBack = 0, options) {
|
|
|
187
216
|
enabled: enabled && !!id
|
|
188
217
|
}))
|
|
189
218
|
});
|
|
190
|
-
const signature = results.map((r) => `${r.status}:${r.dataUpdatedAt ?? 0}`).join("|")
|
|
219
|
+
const signature = results.map((r) => `${r.status}:${r.dataUpdatedAt ?? 0}`).join("|") + `#${projects.dataUpdatedAt}`;
|
|
191
220
|
return React.useMemo(() => {
|
|
192
221
|
const dailyMap = /* @__PURE__ */ new Map();
|
|
193
222
|
const modelMap = /* @__PURE__ */ new Map();
|
|
194
|
-
let
|
|
223
|
+
let totalCredits = 0;
|
|
224
|
+
let anyData = false;
|
|
225
|
+
let anyMetered = false;
|
|
195
226
|
let totalTokens = 0;
|
|
196
227
|
let totalRequests = 0;
|
|
197
|
-
|
|
228
|
+
results.forEach((r, i) => {
|
|
198
229
|
const d = r.data;
|
|
199
|
-
if (!d)
|
|
200
|
-
|
|
230
|
+
if (!d) return;
|
|
231
|
+
anyData = true;
|
|
232
|
+
const subscription = projects.data?.find(
|
|
233
|
+
(p) => p.external_id === projectExtIds[i]
|
|
234
|
+
)?.subscription;
|
|
235
|
+
if (isUsageMetered(d, subscription)) anyMetered = true;
|
|
236
|
+
totalCredits += d.total_spend ?? 0;
|
|
201
237
|
totalTokens += d.total_tokens ?? 0;
|
|
202
238
|
totalRequests += d.total_requests ?? 0;
|
|
203
239
|
for (const day of d.daily ?? []) {
|
|
204
240
|
const cur = dailyMap.get(day.date) ?? {
|
|
205
241
|
date: day.date,
|
|
206
|
-
|
|
242
|
+
credits: 0,
|
|
207
243
|
totalTokens: 0,
|
|
208
244
|
apiRequests: 0
|
|
209
245
|
};
|
|
210
|
-
cur.
|
|
246
|
+
cur.credits += day.spend ?? 0;
|
|
211
247
|
cur.totalTokens += day.total_tokens ?? 0;
|
|
212
248
|
cur.apiRequests += day.api_requests ?? 0;
|
|
213
249
|
dailyMap.set(day.date, cur);
|
|
@@ -215,28 +251,29 @@ function useProjectsUsage(projectExtIds, monthsBack = 0, options) {
|
|
|
215
251
|
for (const [model, mg] of Object.entries(d.model_groups ?? {})) {
|
|
216
252
|
const cur = modelMap.get(model) ?? {
|
|
217
253
|
model,
|
|
218
|
-
|
|
254
|
+
credits: 0,
|
|
219
255
|
totalTokens: 0,
|
|
220
256
|
promptTokens: 0,
|
|
221
257
|
completionTokens: 0,
|
|
222
258
|
successfulRequests: 0
|
|
223
259
|
};
|
|
224
|
-
cur.
|
|
260
|
+
cur.credits += mg.spend ?? 0;
|
|
225
261
|
cur.totalTokens += mg.total_tokens ?? 0;
|
|
226
262
|
cur.promptTokens += mg.prompt_tokens ?? 0;
|
|
227
263
|
cur.completionTokens += mg.completion_tokens ?? 0;
|
|
228
264
|
cur.successfulRequests += mg.successful_requests ?? 0;
|
|
229
265
|
modelMap.set(model, cur);
|
|
230
266
|
}
|
|
231
|
-
}
|
|
267
|
+
});
|
|
232
268
|
return {
|
|
233
|
-
|
|
269
|
+
totalCredits,
|
|
234
270
|
totalTokens,
|
|
235
271
|
totalRequests,
|
|
236
272
|
daily: [...dailyMap.values()].sort((a, b) => a.date.localeCompare(b.date)),
|
|
237
273
|
modelGroups: [...modelMap.values()].sort(
|
|
238
|
-
(a, b) => b.
|
|
274
|
+
(a, b) => b.credits - a.credits || b.totalTokens - a.totalTokens
|
|
239
275
|
),
|
|
276
|
+
metered: !anyData || anyMetered,
|
|
240
277
|
isLoading: results.some((r) => r.isLoading),
|
|
241
278
|
isError: results.some((r) => r.isError)
|
|
242
279
|
};
|
|
@@ -892,6 +929,186 @@ function useArbiShellWorkspaces(options = {}) {
|
|
|
892
929
|
select: select ?? defaultSelect
|
|
893
930
|
});
|
|
894
931
|
}
|
|
932
|
+
function useCreateTask() {
|
|
933
|
+
const arbi = chunk7IOCMCC5_cjs.useArbi();
|
|
934
|
+
const qc = reactQuery.useQueryClient();
|
|
935
|
+
return reactQuery.useMutation({
|
|
936
|
+
mutationFn: (body) => arbi.tasks.create(body),
|
|
937
|
+
onSuccess: () => qc.invalidateQueries({ queryKey: arbiQueryKeys.tasks() })
|
|
938
|
+
});
|
|
939
|
+
}
|
|
940
|
+
function useUpdateTask() {
|
|
941
|
+
const arbi = chunk7IOCMCC5_cjs.useArbi();
|
|
942
|
+
const qc = reactQuery.useQueryClient();
|
|
943
|
+
return reactQuery.useMutation({
|
|
944
|
+
mutationFn: ({ taskId, patch }) => arbi.tasks.update(taskId, patch),
|
|
945
|
+
onSuccess: () => qc.invalidateQueries({ queryKey: arbiQueryKeys.tasks() })
|
|
946
|
+
});
|
|
947
|
+
}
|
|
948
|
+
function useRunTask() {
|
|
949
|
+
const arbi = chunk7IOCMCC5_cjs.useArbi();
|
|
950
|
+
const qc = reactQuery.useQueryClient();
|
|
951
|
+
return reactQuery.useMutation({
|
|
952
|
+
mutationFn: (taskId) => arbi.tasks.runWithAuth(taskId),
|
|
953
|
+
onSuccess: (_task, taskId) => Promise.all([
|
|
954
|
+
qc.invalidateQueries({ queryKey: arbiQueryKeys.tasks() }),
|
|
955
|
+
qc.invalidateQueries({ queryKey: arbiQueryKeys.taskRuns(taskId) })
|
|
956
|
+
])
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
function useDeleteTask() {
|
|
960
|
+
const arbi = chunk7IOCMCC5_cjs.useArbi();
|
|
961
|
+
const qc = reactQuery.useQueryClient();
|
|
962
|
+
return reactQuery.useMutation({
|
|
963
|
+
mutationFn: (taskId) => arbi.tasks.delete(taskId),
|
|
964
|
+
onSuccess: () => qc.invalidateQueries({ queryKey: arbiQueryKeys.tasks() })
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
function useTaskRuns(taskId, options) {
|
|
968
|
+
const arbi = chunk7IOCMCC5_cjs.useArbi();
|
|
969
|
+
return reactQuery.useQuery({
|
|
970
|
+
queryKey: arbiQueryKeys.taskRuns(taskId ?? ""),
|
|
971
|
+
queryFn: () => arbi.tasks.listRuns(taskId),
|
|
972
|
+
enabled: (options?.enabled ?? true) && !!taskId && arbi.isLoggedIn,
|
|
973
|
+
refetchInterval: (q) => q.state.data?.some((r) => r.status === "running") ? 3e3 : false
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
function useCreateAgent() {
|
|
977
|
+
const arbi = chunk7IOCMCC5_cjs.useArbi();
|
|
978
|
+
const qc = reactQuery.useQueryClient();
|
|
979
|
+
return reactQuery.useMutation({
|
|
980
|
+
mutationFn: (name) => arbi.agents.create(name),
|
|
981
|
+
onSuccess: () => qc.invalidateQueries({ queryKey: arbiQueryKeys.agents() })
|
|
982
|
+
});
|
|
983
|
+
}
|
|
984
|
+
function useAgentConfig(agentExtId, options) {
|
|
985
|
+
const arbi = chunk7IOCMCC5_cjs.useArbi();
|
|
986
|
+
return reactQuery.useQuery({
|
|
987
|
+
queryKey: arbiQueryKeys.agentConfig(agentExtId),
|
|
988
|
+
queryFn: async () => agentExtId ? await arbi.agents.getConfig(agentExtId) : await arbi.agentConfig.get("default"),
|
|
989
|
+
enabled: (options?.enabled ?? true) && arbi.isLoggedIn
|
|
990
|
+
});
|
|
991
|
+
}
|
|
992
|
+
function useAgentModels(options) {
|
|
993
|
+
const arbi = chunk7IOCMCC5_cjs.useArbi();
|
|
994
|
+
return reactQuery.useQuery({
|
|
995
|
+
queryKey: arbiQueryKeys.models(),
|
|
996
|
+
queryFn: async () => (await arbi.agentConfig.getModels()).models.map((m) => m.model_name),
|
|
997
|
+
enabled: (options?.enabled ?? true) && arbi.isLoggedIn
|
|
998
|
+
});
|
|
999
|
+
}
|
|
1000
|
+
function useSaveAgentConfig() {
|
|
1001
|
+
const arbi = chunk7IOCMCC5_cjs.useArbi();
|
|
1002
|
+
const qc = reactQuery.useQueryClient();
|
|
1003
|
+
return reactQuery.useMutation({
|
|
1004
|
+
mutationFn: async ({ agentExtId, title, sections }) => {
|
|
1005
|
+
const pinned = await arbi.agents.getConfig(agentExtId);
|
|
1006
|
+
const base = pinned ?? await arbi.agentConfig.get("default");
|
|
1007
|
+
const merged = structuredClone(base);
|
|
1008
|
+
for (const [section, params] of Object.entries(sections)) {
|
|
1009
|
+
merged[section] = { ...merged[section] ?? {}, ...params };
|
|
1010
|
+
}
|
|
1011
|
+
return arbi.agentConfig.save({
|
|
1012
|
+
...merged,
|
|
1013
|
+
agent_ext_id: agentExtId,
|
|
1014
|
+
title: title ?? `agent-${agentExtId}`
|
|
1015
|
+
});
|
|
1016
|
+
},
|
|
1017
|
+
onSuccess: (_saved, { agentExtId }) => Promise.all([
|
|
1018
|
+
qc.invalidateQueries({ queryKey: arbiQueryKeys.configs() }),
|
|
1019
|
+
qc.invalidateQueries({ queryKey: arbiQueryKeys.agentConfig(agentExtId) })
|
|
1020
|
+
])
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
function useAgentWorkspaces(agentExtId, options) {
|
|
1024
|
+
const arbi = chunk7IOCMCC5_cjs.useArbi();
|
|
1025
|
+
return reactQuery.useQuery({
|
|
1026
|
+
queryKey: arbiQueryKeys.agentWorkspaces(agentExtId ?? ""),
|
|
1027
|
+
queryFn: () => arbi.agents.listWorkspaces(agentExtId),
|
|
1028
|
+
enabled: (options?.enabled ?? true) && !!agentExtId && arbi.isLoggedIn
|
|
1029
|
+
});
|
|
1030
|
+
}
|
|
1031
|
+
function useGrantAgentAccess() {
|
|
1032
|
+
const arbi = chunk7IOCMCC5_cjs.useArbi();
|
|
1033
|
+
const qc = reactQuery.useQueryClient();
|
|
1034
|
+
return reactQuery.useMutation({
|
|
1035
|
+
mutationFn: async ({
|
|
1036
|
+
agentExtId,
|
|
1037
|
+
workspaceId,
|
|
1038
|
+
mode = { kind: "standing" }
|
|
1039
|
+
}) => {
|
|
1040
|
+
if (mode.kind === "temporary") {
|
|
1041
|
+
return arbi.agents.grantTemporaryAccess(agentExtId, workspaceId, mode.ttlSeconds);
|
|
1042
|
+
}
|
|
1043
|
+
const agent = (await arbi.agents.list()).find((a) => a.external_id === agentExtId);
|
|
1044
|
+
if (!agent?.email) throw new Error("The agent's address is unknown.");
|
|
1045
|
+
return arbi.workspaces.grantAccess({ workspaceId, emails: [agent.email] });
|
|
1046
|
+
},
|
|
1047
|
+
onSuccess: (_res, { agentExtId }) => qc.invalidateQueries({ queryKey: arbiQueryKeys.agentWorkspaces(agentExtId) })
|
|
1048
|
+
});
|
|
1049
|
+
}
|
|
1050
|
+
function useRevokeAgentAccess() {
|
|
1051
|
+
const arbi = chunk7IOCMCC5_cjs.useArbi();
|
|
1052
|
+
const qc = reactQuery.useQueryClient();
|
|
1053
|
+
return reactQuery.useMutation({
|
|
1054
|
+
mutationFn: async ({
|
|
1055
|
+
agentExtId,
|
|
1056
|
+
workspaceId
|
|
1057
|
+
}) => {
|
|
1058
|
+
const previous = arbi.hasWorkspace ? arbi.getWorkspaceId() : null;
|
|
1059
|
+
await arbi.selectWorkspace(workspaceId);
|
|
1060
|
+
try {
|
|
1061
|
+
await arbi.workspaces.removeUsers([agentExtId]);
|
|
1062
|
+
} finally {
|
|
1063
|
+
if (previous && previous !== workspaceId) await arbi.selectWorkspace(previous);
|
|
1064
|
+
}
|
|
1065
|
+
},
|
|
1066
|
+
onSuccess: (_res, { agentExtId }) => qc.invalidateQueries({ queryKey: arbiQueryKeys.agentWorkspaces(agentExtId) })
|
|
1067
|
+
});
|
|
1068
|
+
}
|
|
1069
|
+
function useSkills(options) {
|
|
1070
|
+
const arbi = chunk7IOCMCC5_cjs.useArbi();
|
|
1071
|
+
return reactQuery.useQuery({
|
|
1072
|
+
queryKey: [...arbiQueryKeys.skills(), options?.includeHidden ?? false],
|
|
1073
|
+
queryFn: () => arbi.assistant.listSkills({ includeHidden: options?.includeHidden }),
|
|
1074
|
+
enabled: (options?.enabled ?? true) && arbi.isLoggedIn,
|
|
1075
|
+
staleTime: 3e4
|
|
1076
|
+
});
|
|
1077
|
+
}
|
|
1078
|
+
function useContacts(options) {
|
|
1079
|
+
const arbi = chunk7IOCMCC5_cjs.useArbi();
|
|
1080
|
+
return reactQuery.useQuery({
|
|
1081
|
+
queryKey: arbiQueryKeys.contacts(),
|
|
1082
|
+
queryFn: () => arbi.contacts.list(),
|
|
1083
|
+
enabled: (options?.enabled ?? true) && arbi.isLoggedIn
|
|
1084
|
+
});
|
|
1085
|
+
}
|
|
1086
|
+
function usePendingContacts(options) {
|
|
1087
|
+
const contacts = useContacts(options);
|
|
1088
|
+
const pending = React.useMemo(
|
|
1089
|
+
() => (contacts.data ?? []).filter(
|
|
1090
|
+
(c) => c.status === "invitation_pending" || c.status === "invitation_expired"
|
|
1091
|
+
),
|
|
1092
|
+
[contacts.data]
|
|
1093
|
+
);
|
|
1094
|
+
return { ...contacts, pending };
|
|
1095
|
+
}
|
|
1096
|
+
function useAddContacts() {
|
|
1097
|
+
const arbi = chunk7IOCMCC5_cjs.useArbi();
|
|
1098
|
+
const qc = reactQuery.useQueryClient();
|
|
1099
|
+
return reactQuery.useMutation({
|
|
1100
|
+
mutationFn: (emails) => arbi.contacts.add(emails),
|
|
1101
|
+
onSuccess: () => qc.invalidateQueries({ queryKey: arbiQueryKeys.contacts() })
|
|
1102
|
+
});
|
|
1103
|
+
}
|
|
1104
|
+
function useRemoveContacts() {
|
|
1105
|
+
const arbi = chunk7IOCMCC5_cjs.useArbi();
|
|
1106
|
+
const qc = reactQuery.useQueryClient();
|
|
1107
|
+
return reactQuery.useMutation({
|
|
1108
|
+
mutationFn: (contactIds) => arbi.contacts.remove(contactIds),
|
|
1109
|
+
onSuccess: () => qc.invalidateQueries({ queryKey: arbiQueryKeys.contacts() })
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
895
1112
|
function useWorkspaceDocs(workspaceId) {
|
|
896
1113
|
const { data: docs = [], isLoading, isError } = useDocuments(workspaceId);
|
|
897
1114
|
const docIds = React.useMemo(
|
|
@@ -3067,7 +3284,6 @@ function isAgentUser(user) {
|
|
|
3067
3284
|
return user.external_id.startsWith("agt-");
|
|
3068
3285
|
}
|
|
3069
3286
|
var DM_QUERY_KEY = ["arbi", "directMessages"];
|
|
3070
|
-
var CONTACTS_QUERY_KEY = ["arbi", "contacts"];
|
|
3071
3287
|
function mergeContacts(threads, contacts) {
|
|
3072
3288
|
const byPeer = /* @__PURE__ */ new Map();
|
|
3073
3289
|
for (const t of threads) byPeer.set(t.peer.external_id, t);
|
|
@@ -3133,7 +3349,7 @@ function useDirectMessages(options) {
|
|
|
3133
3349
|
enabled
|
|
3134
3350
|
});
|
|
3135
3351
|
const contactsQuery = reactQuery.useQuery({
|
|
3136
|
-
queryKey:
|
|
3352
|
+
queryKey: arbiQueryKeys.contacts(),
|
|
3137
3353
|
queryFn: () => arbi.contacts.list(),
|
|
3138
3354
|
enabled
|
|
3139
3355
|
});
|
|
@@ -3218,6 +3434,7 @@ function ConversationList({
|
|
|
3218
3434
|
classNames,
|
|
3219
3435
|
emptyState,
|
|
3220
3436
|
header,
|
|
3437
|
+
lead,
|
|
3221
3438
|
className
|
|
3222
3439
|
}) {
|
|
3223
3440
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -3237,6 +3454,7 @@ function ConversationList({
|
|
|
3237
3454
|
conversations.length === 1 ? "colleague" : "colleagues"
|
|
3238
3455
|
] })
|
|
3239
3456
|
] }) : header,
|
|
3457
|
+
lead,
|
|
3240
3458
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1 overflow-y-auto", children: conversations.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-6 text-xs text-muted-foreground", children: emptyState ?? "No conversations yet." }) : /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "w-full", children: conversations.map((c, i) => {
|
|
3241
3459
|
const { peer, lastMessage, unreadCount } = c;
|
|
3242
3460
|
const newSection = c.sectionLabel && c.sectionLabel !== conversations[i - 1]?.sectionLabel;
|
|
@@ -3523,14 +3741,117 @@ function DmComposer({
|
|
|
3523
3741
|
error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-xs text-destructive", "data-testid": "arbi-dm-error", children: error })
|
|
3524
3742
|
] });
|
|
3525
3743
|
}
|
|
3744
|
+
var DEFAULT_START_BY_EMAIL_LABELS = {
|
|
3745
|
+
email: "Email address",
|
|
3746
|
+
emailPlaceholder: "name@example.com",
|
|
3747
|
+
message: "Message",
|
|
3748
|
+
messagePlaceholder: "Write the first message\u2026",
|
|
3749
|
+
send: "Send",
|
|
3750
|
+
sending: "Sending\u2026",
|
|
3751
|
+
invalidEmail: "Enter a valid email address."
|
|
3752
|
+
};
|
|
3753
|
+
var EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
3754
|
+
function StartByEmail({
|
|
3755
|
+
onStart,
|
|
3756
|
+
onStarted,
|
|
3757
|
+
classNames,
|
|
3758
|
+
labels,
|
|
3759
|
+
className
|
|
3760
|
+
}) {
|
|
3761
|
+
const l = { ...DEFAULT_START_BY_EMAIL_LABELS, ...labels };
|
|
3762
|
+
const uid = React.useId();
|
|
3763
|
+
const [email, setEmail] = React.useState("");
|
|
3764
|
+
const [text, setText] = React.useState("");
|
|
3765
|
+
const [busy, setBusy] = React.useState(false);
|
|
3766
|
+
const [error, setError] = React.useState(null);
|
|
3767
|
+
const address = email.trim().toLowerCase();
|
|
3768
|
+
const valid = EMAIL.test(address);
|
|
3769
|
+
const submit = async () => {
|
|
3770
|
+
if (!valid || !text.trim() || busy) return;
|
|
3771
|
+
setBusy(true);
|
|
3772
|
+
setError(null);
|
|
3773
|
+
try {
|
|
3774
|
+
const result = await onStart(address, text.trim());
|
|
3775
|
+
setEmail("");
|
|
3776
|
+
setText("");
|
|
3777
|
+
onStarted?.(result);
|
|
3778
|
+
} catch (e) {
|
|
3779
|
+
setError(e instanceof Error ? e.message : String(e));
|
|
3780
|
+
} finally {
|
|
3781
|
+
setBusy(false);
|
|
3782
|
+
}
|
|
3783
|
+
};
|
|
3784
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3785
|
+
"form",
|
|
3786
|
+
{
|
|
3787
|
+
"data-testid": "arbi-dm-start",
|
|
3788
|
+
className: chunkRZQACYNQ_cjs.cn("flex flex-col gap-2 border-b border-border px-4 py-3", className),
|
|
3789
|
+
onSubmit: (e) => {
|
|
3790
|
+
e.preventDefault();
|
|
3791
|
+
void submit();
|
|
3792
|
+
},
|
|
3793
|
+
children: [
|
|
3794
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunkORKGCXG3_cjs.Label, { htmlFor: `${uid}-email`, children: l.email }),
|
|
3795
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3796
|
+
chunkORKGCXG3_cjs.Input,
|
|
3797
|
+
{
|
|
3798
|
+
id: `${uid}-email`,
|
|
3799
|
+
type: "email",
|
|
3800
|
+
value: email,
|
|
3801
|
+
onChange: (e) => setEmail(e.target.value),
|
|
3802
|
+
placeholder: l.emailPlaceholder,
|
|
3803
|
+
"aria-invalid": email !== "" && !valid,
|
|
3804
|
+
"aria-describedby": email !== "" && !valid ? `${uid}-bad` : void 0,
|
|
3805
|
+
disabled: busy,
|
|
3806
|
+
"data-testid": "arbi-dm-start-email"
|
|
3807
|
+
}
|
|
3808
|
+
),
|
|
3809
|
+
email !== "" && !valid && /* @__PURE__ */ jsxRuntime.jsx("p", { id: `${uid}-bad`, className: "text-xs text-destructive", children: l.invalidEmail }),
|
|
3810
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunkORKGCXG3_cjs.Label, { htmlFor: `${uid}-text`, children: l.message }),
|
|
3811
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3812
|
+
chunkORKGCXG3_cjs.Textarea,
|
|
3813
|
+
{
|
|
3814
|
+
id: `${uid}-text`,
|
|
3815
|
+
value: text,
|
|
3816
|
+
onChange: (e) => setText(e.target.value),
|
|
3817
|
+
placeholder: l.messagePlaceholder,
|
|
3818
|
+
rows: 2,
|
|
3819
|
+
disabled: busy,
|
|
3820
|
+
"data-testid": "arbi-dm-start-message"
|
|
3821
|
+
}
|
|
3822
|
+
),
|
|
3823
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "text-xs text-destructive", "data-testid": "arbi-dm-start-error", children: error }),
|
|
3824
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3825
|
+
chunkORKGCXG3_cjs.Button,
|
|
3826
|
+
{
|
|
3827
|
+
type: "submit",
|
|
3828
|
+
size: "sm",
|
|
3829
|
+
disabled: !valid || !text.trim() || busy,
|
|
3830
|
+
className: chunkRZQACYNQ_cjs.cn("self-end", classNames?.sendButton),
|
|
3831
|
+
"data-testid": "arbi-dm-start-send",
|
|
3832
|
+
children: [
|
|
3833
|
+
busy ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin", "aria-hidden": true }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "size-4", "aria-hidden": true }),
|
|
3834
|
+
busy ? l.sending : l.send
|
|
3835
|
+
]
|
|
3836
|
+
}
|
|
3837
|
+
)
|
|
3838
|
+
]
|
|
3839
|
+
}
|
|
3840
|
+
);
|
|
3841
|
+
}
|
|
3526
3842
|
function DirectMessages({
|
|
3527
3843
|
className,
|
|
3528
3844
|
classNames,
|
|
3529
3845
|
emptyThread: emptyThread2,
|
|
3530
|
-
emptyList
|
|
3846
|
+
emptyList,
|
|
3847
|
+
listHeader,
|
|
3848
|
+
listLead,
|
|
3849
|
+
startByEmail,
|
|
3850
|
+
hideOwnContact
|
|
3531
3851
|
}) {
|
|
3532
3852
|
const {
|
|
3533
|
-
conversations,
|
|
3853
|
+
conversations: allConversations,
|
|
3854
|
+
myExtId,
|
|
3534
3855
|
isLoading,
|
|
3535
3856
|
isError,
|
|
3536
3857
|
error,
|
|
@@ -3540,6 +3861,14 @@ function DirectMessages({
|
|
|
3540
3861
|
markRead
|
|
3541
3862
|
} = useDirectMessages();
|
|
3542
3863
|
const [selectedPeerId, setSelectedPeerId] = React.useState(null);
|
|
3864
|
+
const conversations = React.useMemo(
|
|
3865
|
+
() => hideOwnContact && myExtId ? allConversations.filter((c) => c.peer.external_id !== myExtId) : allConversations,
|
|
3866
|
+
[allConversations, hideOwnContact, myExtId]
|
|
3867
|
+
);
|
|
3868
|
+
const openStarted = (created) => {
|
|
3869
|
+
const peer = Array.isArray(created) ? created[0]?.recipient?.external_id : void 0;
|
|
3870
|
+
if (peer) setSelectedPeerId(peer);
|
|
3871
|
+
};
|
|
3543
3872
|
const loadError = isError ? error instanceof Error ? error.message : "Couldn\u2019t load messages." : null;
|
|
3544
3873
|
const selected = React.useMemo(
|
|
3545
3874
|
() => conversations.find((c) => c.peer.external_id === selectedPeerId) ?? null,
|
|
@@ -3583,7 +3912,20 @@ function DirectMessages({
|
|
|
3583
3912
|
selectedPeerId: selected?.peer.external_id ?? null,
|
|
3584
3913
|
onSelect: setSelectedPeerId,
|
|
3585
3914
|
classNames,
|
|
3586
|
-
emptyState: isLoading ? "Loading messages\u2026" : emptyList
|
|
3915
|
+
emptyState: isLoading ? "Loading messages\u2026" : emptyList,
|
|
3916
|
+
header: listHeader,
|
|
3917
|
+
lead: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3918
|
+
listLead,
|
|
3919
|
+
startByEmail && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3920
|
+
StartByEmail,
|
|
3921
|
+
{
|
|
3922
|
+
onStart: sendMessageTo,
|
|
3923
|
+
onStarted: openStarted,
|
|
3924
|
+
classNames,
|
|
3925
|
+
labels: typeof startByEmail === "object" ? startByEmail.labels : void 0
|
|
3926
|
+
}
|
|
3927
|
+
)
|
|
3928
|
+
] })
|
|
3587
3929
|
}
|
|
3588
3930
|
),
|
|
3589
3931
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 min-w-0 flex-1 flex-col", children: [
|
|
@@ -5687,6 +6029,8 @@ exports.CommandPalette = CommandPalette;
|
|
|
5687
6029
|
exports.CommandPaletteProvider = CommandPaletteProvider;
|
|
5688
6030
|
exports.ConversationList = ConversationList;
|
|
5689
6031
|
exports.DEFAULT_ASPECT_OPTIONS = DEFAULT_ASPECT_OPTIONS;
|
|
6032
|
+
exports.DEFAULT_START_BY_EMAIL_LABELS = DEFAULT_START_BY_EMAIL_LABELS;
|
|
6033
|
+
exports.DEFAULT_USD_PER_CREDIT = DEFAULT_USD_PER_CREDIT;
|
|
5690
6034
|
exports.DateSeparator = DateSeparator;
|
|
5691
6035
|
exports.DirectMessages = DirectMessages;
|
|
5692
6036
|
exports.DmAvatar = DmAvatar;
|
|
@@ -5716,6 +6060,7 @@ exports.PhotoCapture = PhotoCapture;
|
|
|
5716
6060
|
exports.ProviderIcon = ProviderIcon;
|
|
5717
6061
|
exports.RUN_WINDOW_MS = RUN_WINDOW_MS;
|
|
5718
6062
|
exports.SemanticSearch = SemanticSearch;
|
|
6063
|
+
exports.StartByEmail = StartByEmail;
|
|
5719
6064
|
exports.TxtIcon = TxtIcon;
|
|
5720
6065
|
exports.TypingIndicator = TypingIndicator;
|
|
5721
6066
|
exports.VideoCapture = VideoCapture;
|
|
@@ -5724,14 +6069,17 @@ exports.XlsIcon = XlsIcon;
|
|
|
5724
6069
|
exports.annotateThread = annotateThread;
|
|
5725
6070
|
exports.arbiQueryKeys = arbiQueryKeys;
|
|
5726
6071
|
exports.captureFrameAsBlob = captureFrameAsBlob;
|
|
6072
|
+
exports.creditsToUsd = creditsToUsd;
|
|
5727
6073
|
exports.cropImage = cropImage;
|
|
5728
6074
|
exports.dayKey = dayKey;
|
|
5729
6075
|
exports.describeActivity = describeActivity;
|
|
6076
|
+
exports.formatCredits = formatCredits;
|
|
5730
6077
|
exports.getNotificationTypeMeta = getNotificationTypeMeta;
|
|
5731
6078
|
exports.getWorkspaceActionText = getWorkspaceActionText;
|
|
5732
6079
|
exports.getWorkspaceKind = getWorkspaceKind;
|
|
5733
6080
|
exports.getWorkspaceSentPhrase = getWorkspaceSentPhrase;
|
|
5734
6081
|
exports.hasVideoTrack = hasVideoTrack;
|
|
6082
|
+
exports.isUsageMetered = isUsageMetered;
|
|
5735
6083
|
exports.isWorkspaceNotificationType = isWorkspaceNotificationType;
|
|
5736
6084
|
exports.parseActivityContent = parseActivityContent;
|
|
5737
6085
|
exports.pickRecentWorkspaces = pickRecentWorkspaces;
|
|
@@ -5742,6 +6090,10 @@ exports.titleFromQuestion = titleFromQuestion;
|
|
|
5742
6090
|
exports.toRedlineMarkdown = toRedlineMarkdown;
|
|
5743
6091
|
exports.toShellWorkspace = toShellWorkspace;
|
|
5744
6092
|
exports.useActivity = useActivity;
|
|
6093
|
+
exports.useAddContacts = useAddContacts;
|
|
6094
|
+
exports.useAgentConfig = useAgentConfig;
|
|
6095
|
+
exports.useAgentModels = useAgentModels;
|
|
6096
|
+
exports.useAgentWorkspaces = useAgentWorkspaces;
|
|
5745
6097
|
exports.useAgents = useAgents;
|
|
5746
6098
|
exports.useAiTask = useAiTask;
|
|
5747
6099
|
exports.useArbiChat = useArbiChat;
|
|
@@ -5760,23 +6112,36 @@ exports.useAssistantQuery = useAssistantQuery;
|
|
|
5760
6112
|
exports.useCameraStream = useCameraStream;
|
|
5761
6113
|
exports.useCommandPalette = useCommandPalette;
|
|
5762
6114
|
exports.useConfigs = useConfigs;
|
|
6115
|
+
exports.useContacts = useContacts;
|
|
5763
6116
|
exports.useConversations = useConversations;
|
|
6117
|
+
exports.useCreateAgent = useCreateAgent;
|
|
6118
|
+
exports.useCreateTask = useCreateTask;
|
|
5764
6119
|
exports.useDeleteAgents = useDeleteAgents;
|
|
6120
|
+
exports.useDeleteTask = useDeleteTask;
|
|
5765
6121
|
exports.useDirectMessages = useDirectMessages;
|
|
5766
6122
|
exports.useDocuments = useDocuments;
|
|
5767
6123
|
exports.useFacts = useFacts;
|
|
6124
|
+
exports.useGrantAgentAccess = useGrantAgentAccess;
|
|
5768
6125
|
exports.useHealth = useHealth;
|
|
5769
6126
|
exports.useParsedDocument = useParsedDocument;
|
|
6127
|
+
exports.usePendingContacts = usePendingContacts;
|
|
5770
6128
|
exports.useProjectInvoices = useProjectInvoices;
|
|
5771
6129
|
exports.useProjectUsage = useProjectUsage;
|
|
5772
6130
|
exports.useProjects = useProjects;
|
|
5773
6131
|
exports.useProjectsUsage = useProjectsUsage;
|
|
6132
|
+
exports.useRemoveContacts = useRemoveContacts;
|
|
6133
|
+
exports.useRevokeAgentAccess = useRevokeAgentAccess;
|
|
6134
|
+
exports.useRunTask = useRunTask;
|
|
6135
|
+
exports.useSaveAgentConfig = useSaveAgentConfig;
|
|
5774
6136
|
exports.useSemanticSearch = useSemanticSearch;
|
|
5775
6137
|
exports.useSessions = useSessions;
|
|
5776
6138
|
exports.useShellWorkspaces = useShellWorkspaces;
|
|
6139
|
+
exports.useSkills = useSkills;
|
|
5777
6140
|
exports.useTags = useTags;
|
|
6141
|
+
exports.useTaskRuns = useTaskRuns;
|
|
5778
6142
|
exports.useTasks = useTasks;
|
|
5779
6143
|
exports.useThumbnails = useThumbnails;
|
|
6144
|
+
exports.useUpdateTask = useUpdateTask;
|
|
5780
6145
|
exports.useUserUsageToday = useUserUsageToday;
|
|
5781
6146
|
exports.useVideoRecorder = useVideoRecorder;
|
|
5782
6147
|
exports.useWorkspaceDocs = useWorkspaceDocs;
|