@devicai/ui 0.40.3 → 0.41.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.
Files changed (70) hide show
  1. package/README.md +74 -1
  2. package/dist/cjs/api/client.js +125 -6
  3. package/dist/cjs/api/client.js.map +1 -1
  4. package/dist/cjs/components/AICommandBar/AICommandBar.js +4 -2
  5. package/dist/cjs/components/AICommandBar/AICommandBar.js.map +1 -1
  6. package/dist/cjs/components/AICommandBar/useAICommandBar.js +4 -2
  7. package/dist/cjs/components/AICommandBar/useAICommandBar.js.map +1 -1
  8. package/dist/cjs/components/AIElementWrapper/useAIElementWrapper.js +4 -2
  9. package/dist/cjs/components/AIElementWrapper/useAIElementWrapper.js.map +1 -1
  10. package/dist/cjs/components/AIGenerationButton/useAIGenerationButton.js +4 -2
  11. package/dist/cjs/components/AIGenerationButton/useAIGenerationButton.js.map +1 -1
  12. package/dist/cjs/components/ChatDrawer/ChatDrawer.js +18 -9
  13. package/dist/cjs/components/ChatDrawer/ChatDrawer.js.map +1 -1
  14. package/dist/cjs/components/ChatDrawer/ChatInput.js +9 -3
  15. package/dist/cjs/components/ChatDrawer/ChatInput.js.map +1 -1
  16. package/dist/cjs/components/ChatDrawer/ChatMessages.js +9 -3
  17. package/dist/cjs/components/ChatDrawer/ChatMessages.js.map +1 -1
  18. package/dist/cjs/components/ChatDrawer/ConversationSelector.js +9 -7
  19. package/dist/cjs/components/ChatDrawer/ConversationSelector.js.map +1 -1
  20. package/dist/cjs/components/ChatDrawer/HandoffSubagentWidget.js +10 -3
  21. package/dist/cjs/components/ChatDrawer/HandoffSubagentWidget.js.map +1 -1
  22. package/dist/cjs/components/ChatDrawer/UsageBar.js +8 -2
  23. package/dist/cjs/components/ChatDrawer/UsageBar.js.map +1 -1
  24. package/dist/cjs/components/CoreMemoryModal/CoreMemoryModal.js +7 -3
  25. package/dist/cjs/components/CoreMemoryModal/CoreMemoryModal.js.map +1 -1
  26. package/dist/cjs/components/IntegrationsModal/useIntegrations.js +12 -5
  27. package/dist/cjs/components/IntegrationsModal/useIntegrations.js.map +1 -1
  28. package/dist/cjs/components/ThreadStateTag/ThreadStateTag.js +10 -3
  29. package/dist/cjs/components/ThreadStateTag/ThreadStateTag.js.map +1 -1
  30. package/dist/cjs/hooks/useDevicChat.js +4 -2
  31. package/dist/cjs/hooks/useDevicChat.js.map +1 -1
  32. package/dist/cjs/provider/DevicProvider.js +27 -3
  33. package/dist/cjs/provider/DevicProvider.js.map +1 -1
  34. package/dist/esm/api/client.d.ts +63 -3
  35. package/dist/esm/api/client.js +125 -6
  36. package/dist/esm/api/client.js.map +1 -1
  37. package/dist/esm/components/AICommandBar/AICommandBar.js +4 -2
  38. package/dist/esm/components/AICommandBar/AICommandBar.js.map +1 -1
  39. package/dist/esm/components/AICommandBar/useAICommandBar.js +4 -2
  40. package/dist/esm/components/AICommandBar/useAICommandBar.js.map +1 -1
  41. package/dist/esm/components/AIElementWrapper/useAIElementWrapper.js +4 -2
  42. package/dist/esm/components/AIElementWrapper/useAIElementWrapper.js.map +1 -1
  43. package/dist/esm/components/AIGenerationButton/useAIGenerationButton.js +4 -2
  44. package/dist/esm/components/AIGenerationButton/useAIGenerationButton.js.map +1 -1
  45. package/dist/esm/components/ChatDrawer/ChatDrawer.js +18 -9
  46. package/dist/esm/components/ChatDrawer/ChatDrawer.js.map +1 -1
  47. package/dist/esm/components/ChatDrawer/ChatInput.js +9 -3
  48. package/dist/esm/components/ChatDrawer/ChatInput.js.map +1 -1
  49. package/dist/esm/components/ChatDrawer/ChatMessages.js +9 -3
  50. package/dist/esm/components/ChatDrawer/ChatMessages.js.map +1 -1
  51. package/dist/esm/components/ChatDrawer/ConversationSelector.js +9 -7
  52. package/dist/esm/components/ChatDrawer/ConversationSelector.js.map +1 -1
  53. package/dist/esm/components/ChatDrawer/HandoffSubagentWidget.js +10 -3
  54. package/dist/esm/components/ChatDrawer/HandoffSubagentWidget.js.map +1 -1
  55. package/dist/esm/components/ChatDrawer/UsageBar.js +8 -2
  56. package/dist/esm/components/ChatDrawer/UsageBar.js.map +1 -1
  57. package/dist/esm/components/CoreMemoryModal/CoreMemoryModal.js +7 -3
  58. package/dist/esm/components/CoreMemoryModal/CoreMemoryModal.js.map +1 -1
  59. package/dist/esm/components/IntegrationsModal/useIntegrations.js +12 -5
  60. package/dist/esm/components/IntegrationsModal/useIntegrations.js.map +1 -1
  61. package/dist/esm/components/ThreadStateTag/ThreadStateTag.js +10 -3
  62. package/dist/esm/components/ThreadStateTag/ThreadStateTag.js.map +1 -1
  63. package/dist/esm/hooks/useDevicChat.js +4 -2
  64. package/dist/esm/hooks/useDevicChat.js.map +1 -1
  65. package/dist/esm/index.d.ts +1 -1
  66. package/dist/esm/provider/DevicProvider.d.ts +1 -1
  67. package/dist/esm/provider/DevicProvider.js +27 -3
  68. package/dist/esm/provider/DevicProvider.js.map +1 -1
  69. package/dist/esm/provider/types.d.ts +62 -5
  70. package/package.json +1 -1
@@ -22,7 +22,7 @@ const DEFAULT_BASE_URL = 'https://api.devic.ai';
22
22
  * </DevicProvider>
23
23
  * ```
24
24
  */
25
- function DevicProvider({ apiKey, baseUrl = DEFAULT_BASE_URL, tenantId, tenantMetadata, subtenantId, subtenantMetadata, tags, debug, children, }) {
25
+ function DevicProvider({ apiKey, getTenantSession, onSessionExpired, baseUrl = DEFAULT_BASE_URL, tenantId, tenantMetadata, subtenantId, subtenantMetadata, tags, debug, children, }) {
26
26
  const [references, setReferences] = React.useState([]);
27
27
  const drawerRef = React.useRef(null);
28
28
  const addReference = React.useCallback((ref) => {
@@ -47,17 +47,38 @@ function DevicProvider({ apiKey, baseUrl = DEFAULT_BASE_URL, tenantId, tenantMet
47
47
  const openDrawer = React.useCallback(() => {
48
48
  drawerRef.current?.open();
49
49
  }, []);
50
- const client$1 = React.useMemo(() => new client.DevicApiClient({ apiKey, baseUrl }), [apiKey, baseUrl]);
50
+ // Both callbacks are read through a ref and handed on as stable wrappers.
51
+ // An inline `getTenantSession={() => …}` is a new function on every render,
52
+ // and passing it straight through would rebuild the client — throwing away
53
+ // the session it holds, so the page fetches a token per render — and rebuild
54
+ // the context, so every component below it would do the same.
55
+ const sessionSourceRef = React.useRef(getTenantSession);
56
+ sessionSourceRef.current = getTenantSession;
57
+ const expiredRef = React.useRef(onSessionExpired);
58
+ expiredRef.current = onSessionExpired;
59
+ const usesSessions = !!getTenantSession;
60
+ const tenantSession = React.useMemo(() => usesSessions
61
+ ? () => sessionSourceRef.current()
62
+ : undefined, [usesSessions]);
63
+ const sessionExpired = React.useMemo(() => () => expiredRef.current?.(), []);
64
+ const client$1 = React.useMemo(() => new client.DevicApiClient({
65
+ apiKey,
66
+ baseUrl,
67
+ getTenantSession: tenantSession,
68
+ onSessionExpired: sessionExpired,
69
+ }), [apiKey, baseUrl, tenantSession, sessionExpired]);
51
70
  const contextValue = React.useMemo(() => ({
52
71
  client: client$1,
53
72
  apiKey,
73
+ getTenantSession: tenantSession,
74
+ onSessionExpired: sessionExpired,
54
75
  baseUrl,
55
76
  tenantId,
56
77
  tenantMetadata,
57
78
  subtenantId,
58
79
  subtenantMetadata,
59
80
  tags,
60
- isConfigured: !!apiKey,
81
+ isConfigured: !!apiKey || usesSessions,
61
82
  debug,
62
83
  references,
63
84
  addReference,
@@ -68,6 +89,9 @@ function DevicProvider({ apiKey, baseUrl = DEFAULT_BASE_URL, tenantId, tenantMet
68
89
  }), [
69
90
  client$1,
70
91
  apiKey,
92
+ tenantSession,
93
+ sessionExpired,
94
+ usesSessions,
71
95
  baseUrl,
72
96
  tenantId,
73
97
  tenantMetadata,
@@ -1 +1 @@
1
- {"version":3,"file":"DevicProvider.js","sources":["../../../../src/provider/DevicProvider.tsx"],"sourcesContent":["import React, { useMemo, useState, useRef, useCallback } from 'react';\nimport { DevicContext } from './DevicContext';\nimport { DevicApiClient } from '../api/client';\nimport { generateId } from '../utils';\nimport type {\n DevicProviderProps,\n DevicContextValue,\n AIReference,\n DrawerRegistration,\n} from './types';\n\nconst DEFAULT_BASE_URL = 'https://api.devic.ai';\n\n/**\n * Provider component for Devic UI configuration\n *\n * @example\n * ```tsx\n * <DevicProvider\n * apiKey=\"devic-xxx\"\n * baseUrl=\"https://api.devic.ai\"\n * tenantId=\"tenant-123\"\n * tenantMetadata={{ userId: '456' }}\n * >\n * <App />\n * </DevicProvider>\n * ```\n */\nexport function DevicProvider({\n apiKey,\n baseUrl = DEFAULT_BASE_URL,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n tags,\n debug,\n children,\n}: DevicProviderProps): JSX.Element {\n const [references, setReferences] = useState<AIReference[]>([]);\n const drawerRef = useRef<DrawerRegistration | null>(null);\n\n const addReference = useCallback((ref: Omit<AIReference, 'id'>): string => {\n const id = generateId();\n setReferences((prev) => [...prev, { ...ref, id }]);\n return id;\n }, []);\n\n const removeReference = useCallback((id: string) => {\n setReferences((prev) => prev.filter((r) => r.id !== id));\n }, []);\n\n const clearReferences = useCallback(() => {\n setReferences([]);\n }, []);\n\n const registerDrawer = useCallback((handle: DrawerRegistration) => {\n drawerRef.current = handle;\n return () => {\n if (drawerRef.current === handle) {\n drawerRef.current = null;\n }\n };\n }, []);\n\n const openDrawer = useCallback(() => {\n drawerRef.current?.open();\n }, []);\n\n const client = useMemo(\n () => new DevicApiClient({ apiKey, baseUrl }),\n [apiKey, baseUrl]\n );\n\n const contextValue = useMemo<DevicContextValue>(\n () => ({\n client,\n apiKey,\n baseUrl,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n tags,\n isConfigured: !!apiKey,\n debug,\n references,\n addReference,\n removeReference,\n clearReferences,\n registerDrawer,\n openDrawer,\n }),\n [\n client,\n apiKey,\n baseUrl,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n tags,\n debug,\n references,\n addReference,\n removeReference,\n clearReferences,\n registerDrawer,\n openDrawer,\n ]\n );\n\n return (\n <DevicContext.Provider value={contextValue}>\n {children}\n </DevicContext.Provider>\n );\n}\n"],"names":["useState","useRef","useCallback","generateId","client","useMemo","DevicApiClient","_jsx","DevicContext"],"mappings":";;;;;;;;AAWA,MAAM,gBAAgB,GAAG,sBAAsB;AAE/C;;;;;;;;;;;;;;AAcG;AACG,SAAU,aAAa,CAAC,EAC5B,MAAM,EACN,OAAO,GAAG,gBAAgB,EAC1B,QAAQ,EACR,cAAc,EACd,WAAW,EACX,iBAAiB,EACjB,IAAI,EACJ,KAAK,EACL,QAAQ,GACW,EAAA;IACnB,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAGA,cAAQ,CAAgB,EAAE,CAAC;AAC/D,IAAA,MAAM,SAAS,GAAGC,YAAM,CAA4B,IAAI,CAAC;AAEzD,IAAA,MAAM,YAAY,GAAGC,iBAAW,CAAC,CAAC,GAA4B,KAAY;AACxE,QAAA,MAAM,EAAE,GAAGC,gBAAU,EAAE;AACvB,QAAA,aAAa,CAAC,CAAC,IAAI,KAAK,CAAC,GAAG,IAAI,EAAE,EAAE,GAAG,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;AAClD,QAAA,OAAO,EAAE;IACX,CAAC,EAAE,EAAE,CAAC;AAEN,IAAA,MAAM,eAAe,GAAGD,iBAAW,CAAC,CAAC,EAAU,KAAI;QACjD,aAAa,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IAC1D,CAAC,EAAE,EAAE,CAAC;AAEN,IAAA,MAAM,eAAe,GAAGA,iBAAW,CAAC,MAAK;QACvC,aAAa,CAAC,EAAE,CAAC;IACnB,CAAC,EAAE,EAAE,CAAC;AAEN,IAAA,MAAM,cAAc,GAAGA,iBAAW,CAAC,CAAC,MAA0B,KAAI;AAChE,QAAA,SAAS,CAAC,OAAO,GAAG,MAAM;AAC1B,QAAA,OAAO,MAAK;AACV,YAAA,IAAI,SAAS,CAAC,OAAO,KAAK,MAAM,EAAE;AAChC,gBAAA,SAAS,CAAC,OAAO,GAAG,IAAI;YAC1B;AACF,QAAA,CAAC;IACH,CAAC,EAAE,EAAE,CAAC;AAEN,IAAA,MAAM,UAAU,GAAGA,iBAAW,CAAC,MAAK;AAClC,QAAA,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE;IAC3B,CAAC,EAAE,EAAE,CAAC;IAEN,MAAME,QAAM,GAAGC,aAAO,CACpB,MAAM,IAAIC,qBAAc,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAC7C,CAAC,MAAM,EAAE,OAAO,CAAC,CAClB;AAED,IAAA,MAAM,YAAY,GAAGD,aAAO,CAC1B,OAAO;gBACLD,QAAM;QACN,MAAM;QACN,OAAO;QACP,QAAQ;QACR,cAAc;QACd,WAAW;QACX,iBAAiB;QACjB,IAAI;QACJ,YAAY,EAAE,CAAC,CAAC,MAAM;QACtB,KAAK;QACL,UAAU;QACV,YAAY;QACZ,eAAe;QACf,eAAe;QACf,cAAc;QACd,UAAU;AACX,KAAA,CAAC,EACF;QACEA,QAAM;QACN,MAAM;QACN,OAAO;QACP,QAAQ;QACR,cAAc;QACd,WAAW;QACX,iBAAiB;QACjB,IAAI;QACJ,KAAK;QACL,UAAU;QACV,YAAY;QACZ,eAAe;QACf,eAAe;QACf,cAAc;QACd,UAAU;AACX,KAAA,CACF;AAED,IAAA,QACEG,cAAA,CAACC,yBAAY,CAAC,QAAQ,EAAA,EAAC,KAAK,EAAE,YAAY,EAAA,QAAA,EACvC,QAAQ,EAAA,CACa;AAE5B;;;;"}
1
+ {"version":3,"file":"DevicProvider.js","sources":["../../../../src/provider/DevicProvider.tsx"],"sourcesContent":["import React, { useMemo, useState, useRef, useCallback } from 'react';\nimport { DevicContext } from './DevicContext';\nimport { DevicApiClient } from '../api/client';\nimport { generateId } from '../utils';\nimport type {\n DevicProviderProps,\n DevicContextValue,\n AIReference,\n DrawerRegistration,\n} from './types';\n\nconst DEFAULT_BASE_URL = 'https://api.devic.ai';\n\n/**\n * Provider component for Devic UI configuration\n *\n * @example\n * ```tsx\n * <DevicProvider\n * apiKey=\"devic-xxx\"\n * baseUrl=\"https://api.devic.ai\"\n * tenantId=\"tenant-123\"\n * tenantMetadata={{ userId: '456' }}\n * >\n * <App />\n * </DevicProvider>\n * ```\n */\nexport function DevicProvider({\n apiKey,\n getTenantSession,\n onSessionExpired,\n baseUrl = DEFAULT_BASE_URL,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n tags,\n debug,\n children,\n}: DevicProviderProps): JSX.Element {\n const [references, setReferences] = useState<AIReference[]>([]);\n const drawerRef = useRef<DrawerRegistration | null>(null);\n\n const addReference = useCallback((ref: Omit<AIReference, 'id'>): string => {\n const id = generateId();\n setReferences((prev) => [...prev, { ...ref, id }]);\n return id;\n }, []);\n\n const removeReference = useCallback((id: string) => {\n setReferences((prev) => prev.filter((r) => r.id !== id));\n }, []);\n\n const clearReferences = useCallback(() => {\n setReferences([]);\n }, []);\n\n const registerDrawer = useCallback((handle: DrawerRegistration) => {\n drawerRef.current = handle;\n return () => {\n if (drawerRef.current === handle) {\n drawerRef.current = null;\n }\n };\n }, []);\n\n const openDrawer = useCallback(() => {\n drawerRef.current?.open();\n }, []);\n\n // Both callbacks are read through a ref and handed on as stable wrappers.\n // An inline `getTenantSession={() => …}` is a new function on every render,\n // and passing it straight through would rebuild the client — throwing away\n // the session it holds, so the page fetches a token per render — and rebuild\n // the context, so every component below it would do the same.\n const sessionSourceRef = useRef(getTenantSession);\n sessionSourceRef.current = getTenantSession;\n const expiredRef = useRef(onSessionExpired);\n expiredRef.current = onSessionExpired;\n const usesSessions = !!getTenantSession;\n\n const tenantSession = useMemo(\n () =>\n usesSessions\n ? () => sessionSourceRef.current!()\n : undefined,\n [usesSessions]\n );\n const sessionExpired = useMemo(() => () => expiredRef.current?.(), []);\n\n const client = useMemo(\n () =>\n new DevicApiClient({\n apiKey,\n baseUrl,\n getTenantSession: tenantSession,\n onSessionExpired: sessionExpired,\n }),\n [apiKey, baseUrl, tenantSession, sessionExpired]\n );\n\n const contextValue = useMemo<DevicContextValue>(\n () => ({\n client,\n apiKey,\n getTenantSession: tenantSession,\n onSessionExpired: sessionExpired,\n baseUrl,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n tags,\n isConfigured: !!apiKey || usesSessions,\n debug,\n references,\n addReference,\n removeReference,\n clearReferences,\n registerDrawer,\n openDrawer,\n }),\n [\n client,\n apiKey,\n tenantSession,\n sessionExpired,\n usesSessions,\n baseUrl,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n tags,\n debug,\n references,\n addReference,\n removeReference,\n clearReferences,\n registerDrawer,\n openDrawer,\n ]\n );\n\n return (\n <DevicContext.Provider value={contextValue}>\n {children}\n </DevicContext.Provider>\n );\n}\n"],"names":["useState","useRef","useCallback","generateId","useMemo","client","DevicApiClient","_jsx","DevicContext"],"mappings":"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"}
@@ -1,18 +1,78 @@
1
1
  import type { ProcessMessageDto, ChatMessage, AsyncResponse, RealtimeChatHistory, ChatHistory, AssistantSpecialization, ApiError, ToolCallResponse, ListConversationsResponse, FeedbackSubmission, FeedbackEntry, AgentThreadDto, AgentDto, WhisperTranscriptionResponse, TenantUsage, TenantUsageHistoryRow, TenantUsageHistoryQuery, CoreMemoryList, CoreMemoryEntry, Integration } from "./types";
2
+ /**
3
+ * A tenant session, as the integrator's backend hands it over.
4
+ *
5
+ * A bare string is accepted too — the expiry is then read out of the token
6
+ * itself, so the simplest possible source still gets proactive renewal.
7
+ */
8
+ export interface TenantSessionToken {
9
+ token: string;
10
+ /** Epoch milliseconds. */
11
+ expiresAt?: number;
12
+ /** Seconds from now. Used when `expiresAt` is absent. */
13
+ expiresIn?: number;
14
+ }
2
15
  export interface DevicApiClientConfig {
3
- apiKey: string;
16
+ /**
17
+ * The public API key. Optional when `getTenantSession` is supplied — a page
18
+ * using tenant sessions has no reason to carry one.
19
+ */
20
+ apiKey?: string;
4
21
  baseUrl: string;
22
+ /**
23
+ * Where the tenant session comes from.
24
+ *
25
+ * Supplying this changes what the tenant IS: with an API key alone the tenant
26
+ * is whatever the page says it is, and the page can say anything. With a
27
+ * session it is what your server signed.
28
+ *
29
+ * A function rather than a value because it is called again on its own —
30
+ * before the token expires and after the API rejects one. It does not have to
31
+ * reach your backend: reading a cookie your login already set is a perfectly
32
+ * good answer, and then the whole thing is `async () => readCookie(…)`.
33
+ */
34
+ getTenantSession?: () => Promise<string | TenantSessionToken>;
35
+ /**
36
+ * Called when the session is dead and cannot be replaced — the API rejected
37
+ * it and `getTenantSession` handed back the same expired token.
38
+ *
39
+ * Matters most when the session comes from a cookie with no way to renew it:
40
+ * without this the widget simply stops answering, at the exact moment the
41
+ * user's own login has also expired. Refresh the page, send them to log in,
42
+ * or say something — but say it.
43
+ */
44
+ onSessionExpired?: () => void;
5
45
  }
6
46
  /**
7
47
  * Devic API client using native fetch
8
48
  */
9
49
  export declare class DevicApiClient {
10
50
  private config;
51
+ private session?;
52
+ /** In flight renewal, shared so a burst of calls fetches one token. */
53
+ private renewing?;
54
+ /** So a page full of widgets reports one expiry, not one per widget. */
55
+ private expiryReported;
11
56
  constructor(config: DevicApiClientConfig);
12
57
  /**
13
58
  * Update client configuration
14
59
  */
15
60
  setConfig(config: Partial<DevicApiClientConfig>): void;
61
+ /** The credential for the next request, renewed if it is about to expire. */
62
+ private authorization;
63
+ private renew;
64
+ /**
65
+ * Whether a rejected request is worth retrying, having got a live session.
66
+ *
67
+ * Takes the token the request actually went out with, not the current one:
68
+ * with several requests in flight another may already have replaced it, and
69
+ * comparing against the current one would read that success as a failure.
70
+ *
71
+ * False means the session is dead and cannot be replaced — a cookie set at
72
+ * login, now expired, with nowhere to renew it from. That is worth telling
73
+ * the host application about, once.
74
+ */
75
+ private recoverSession;
16
76
  /**
17
77
  * Make an authenticated request to the API
18
78
  */
@@ -113,7 +173,7 @@ export declare class DevicApiClient {
113
173
  /**
114
174
  * Upload a file and get a download URL
115
175
  */
116
- uploadFile(file: File): Promise<{
176
+ uploadFile(file: File, isRetry?: boolean): Promise<{
117
177
  name: string;
118
178
  downloadUrl: string;
119
179
  fileType: string;
@@ -131,7 +191,7 @@ export declare class DevicApiClient {
131
191
  chatUid?: string;
132
192
  tenantId?: string;
133
193
  fileName?: string;
134
- }): Promise<WhisperTranscriptionResponse>;
194
+ }, isRetry?: boolean): Promise<WhisperTranscriptionResponse>;
135
195
  /**
136
196
  * Fetch a single speech-to-text transcript by its id (the `transcriptId`
137
197
  * stored on a message). Returns the transcribed text and the download URL of
@@ -1,24 +1,122 @@
1
+ /** Renew this long before expiry, so a request never leaves with a dead token. */
2
+ const RENEWAL_MARGIN_MS = 60000;
3
+ /**
4
+ * The expiry inside a JWT, in epoch milliseconds.
5
+ *
6
+ * Read rather than required, so the session source can return just the string.
7
+ * Any failure means "no idea", and the token is then renewed only when the API
8
+ * rejects it — correct, just less graceful.
9
+ */
10
+ function expiryOf(token) {
11
+ try {
12
+ const payload = token.split(".")[1];
13
+ if (!payload)
14
+ return undefined;
15
+ const json = atob(payload.replace(/-/g, "+").replace(/_/g, "/"));
16
+ const exp = JSON.parse(json)?.exp;
17
+ return typeof exp === "number" ? exp * 1000 : undefined;
18
+ }
19
+ catch {
20
+ return undefined;
21
+ }
22
+ }
1
23
  /**
2
24
  * Devic API client using native fetch
3
25
  */
4
26
  class DevicApiClient {
5
27
  constructor(config) {
28
+ /** So a page full of widgets reports one expiry, not one per widget. */
29
+ this.expiryReported = false;
6
30
  this.config = config;
7
31
  }
8
32
  /**
9
33
  * Update client configuration
10
34
  */
11
35
  setConfig(config) {
36
+ const previous = this.config;
12
37
  this.config = { ...this.config, ...config };
38
+ // A new session source speaks for a different end user; keeping the old
39
+ // token would show them the previous one's conversations.
40
+ if (config.getTenantSession &&
41
+ config.getTenantSession !== previous.getTenantSession) {
42
+ this.session = undefined;
43
+ this.expiryReported = false;
44
+ }
45
+ }
46
+ /** The credential for the next request, renewed if it is about to expire. */
47
+ async authorization(force = false) {
48
+ if (!this.config.getTenantSession)
49
+ return this.config.apiKey ?? "";
50
+ const current = this.session;
51
+ const stillGood = current &&
52
+ (current.expiresAt === undefined ||
53
+ current.expiresAt - Date.now() > RENEWAL_MARGIN_MS);
54
+ if (stillGood && !force)
55
+ return current.token;
56
+ return this.renew();
57
+ }
58
+ renew() {
59
+ if (!this.renewing) {
60
+ this.renewing = Promise.resolve(this.config.getTenantSession())
61
+ .then((result) => {
62
+ const token = typeof result === "string" ? result : result.token;
63
+ const declared = typeof result === "string"
64
+ ? undefined
65
+ : (result.expiresAt ??
66
+ (result.expiresIn
67
+ ? Date.now() + result.expiresIn * 1000
68
+ : undefined));
69
+ this.session = { token, expiresAt: declared ?? expiryOf(token) };
70
+ return token;
71
+ })
72
+ .finally(() => {
73
+ this.renewing = undefined;
74
+ });
75
+ }
76
+ return this.renewing;
77
+ }
78
+ /**
79
+ * Whether a rejected request is worth retrying, having got a live session.
80
+ *
81
+ * Takes the token the request actually went out with, not the current one:
82
+ * with several requests in flight another may already have replaced it, and
83
+ * comparing against the current one would read that success as a failure.
84
+ *
85
+ * False means the session is dead and cannot be replaced — a cookie set at
86
+ * login, now expired, with nowhere to renew it from. That is worth telling
87
+ * the host application about, once.
88
+ */
89
+ async recoverSession(rejected) {
90
+ if (this.session && this.session.token !== rejected) {
91
+ this.expiryReported = false;
92
+ return true;
93
+ }
94
+ let fresh;
95
+ try {
96
+ fresh = await this.renew();
97
+ }
98
+ catch {
99
+ fresh = undefined;
100
+ }
101
+ if (fresh && fresh !== rejected) {
102
+ this.expiryReported = false;
103
+ return true;
104
+ }
105
+ if (!this.expiryReported) {
106
+ this.expiryReported = true;
107
+ this.config.onSessionExpired?.();
108
+ }
109
+ return false;
13
110
  }
14
111
  /**
15
112
  * Make an authenticated request to the API
16
113
  */
17
- async request(endpoint, options = {}) {
114
+ async request(endpoint, options = {}, isRetry = false) {
18
115
  const url = `${this.config.baseUrl}${endpoint}`;
116
+ const credential = await this.authorization();
19
117
  const headers = {
20
118
  "Content-Type": "application/json",
21
- Authorization: `Bearer ${this.config.apiKey}`,
119
+ Authorization: `Bearer ${credential}`,
22
120
  "devic-api-source": "ui",
23
121
  ...options.headers,
24
122
  };
@@ -26,6 +124,14 @@ class DevicApiClient {
26
124
  ...options,
27
125
  headers,
28
126
  });
127
+ // A session can die between being checked and being used — a clock adrift,
128
+ // a tab asleep for an hour, the key revoked. One retry with a fresh token
129
+ // turns that into a pause instead of a broken conversation.
130
+ if (response.status === 401 && this.config.getTenantSession && !isRetry) {
131
+ if (await this.recoverSession(credential)) {
132
+ return this.request(endpoint, options, true);
133
+ }
134
+ }
29
135
  if (!response.ok) {
30
136
  let errorData;
31
137
  try {
@@ -222,18 +328,25 @@ class DevicApiClient {
222
328
  /**
223
329
  * Upload a file and get a download URL
224
330
  */
225
- async uploadFile(file) {
331
+ async uploadFile(file, isRetry = false) {
226
332
  const url = `${this.config.baseUrl}/api/v1/files/upload`;
227
333
  const formData = new FormData();
228
334
  formData.append("file", file);
335
+ const credential = await this.authorization();
229
336
  const response = await fetch(url, {
230
337
  method: "POST",
231
338
  headers: {
232
- Authorization: `Bearer ${this.config.apiKey}`,
339
+ Authorization: `Bearer ${credential}`,
233
340
  "devic-api-source": "ui",
234
341
  },
235
342
  body: formData,
236
343
  });
344
+ // The FormData is rebuilt from `file` on the way back in, so unlike a
345
+ // consumed stream this retry is safe.
346
+ if (response.status === 401 && this.config.getTenantSession && !isRetry) {
347
+ if (await this.recoverSession(credential))
348
+ return this.uploadFile(file, true);
349
+ }
237
350
  if (!response.ok) {
238
351
  let errorData;
239
352
  try {
@@ -260,7 +373,7 @@ class DevicApiClient {
260
373
  * and runs speech-to-text with Devic's own OpenAI key. Returns the text and a
261
374
  * `transcriptId` to attach to the resulting message.
262
375
  */
263
- async transcribeAudio(audio, options) {
376
+ async transcribeAudio(audio, options, isRetry = false) {
264
377
  const url = `${this.config.baseUrl}/api/v1/whisper`;
265
378
  const formData = new FormData();
266
379
  if (typeof audio === "string") {
@@ -277,14 +390,20 @@ class DevicApiClient {
277
390
  formData.append("chatUid", options.chatUid);
278
391
  if (options?.tenantId)
279
392
  formData.append("tenantId", options.tenantId);
393
+ const credential = await this.authorization();
280
394
  const response = await fetch(url, {
281
395
  method: "POST",
282
396
  headers: {
283
- Authorization: `Bearer ${this.config.apiKey}`,
397
+ Authorization: `Bearer ${credential}`,
284
398
  "devic-api-source": "ui",
285
399
  },
286
400
  body: formData,
287
401
  });
402
+ if (response.status === 401 && this.config.getTenantSession && !isRetry) {
403
+ if (await this.recoverSession(credential)) {
404
+ return this.transcribeAudio(audio, options, true);
405
+ }
406
+ }
288
407
  if (!response.ok) {
289
408
  let errorData;
290
409
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sources":["../../../src/api/client.ts"],"sourcesContent":["import type {\n ProcessMessageDto,\n ChatMessage,\n AsyncResponse,\n RealtimeChatHistory,\n ChatHistory,\n AssistantSpecialization,\n ApiError,\n ToolCallResponse,\n ConversationSummary,\n ListConversationsResponse,\n FeedbackSubmission,\n FeedbackEntry,\n AgentThreadDto,\n AgentDto,\n WhisperTranscriptionResponse,\n TenantUsage,\n TenantUsageHistoryRow,\n TenantUsageHistoryQuery,\n CoreMemoryList,\n CoreMemoryEntry,\n Integration,\n} from \"./types\";\n\nexport interface DevicApiClientConfig {\n apiKey: string;\n baseUrl: string;\n}\n\n/**\n * Devic API client using native fetch\n */\nexport class DevicApiClient {\n private config: DevicApiClientConfig;\n\n constructor(config: DevicApiClientConfig) {\n this.config = config;\n }\n\n /**\n * Update client configuration\n */\n setConfig(config: Partial<DevicApiClientConfig>): void {\n this.config = { ...this.config, ...config };\n }\n\n /**\n * Make an authenticated request to the API\n */\n private async request<T>(\n endpoint: string,\n options: RequestInit = {},\n ): Promise<T> {\n const url = `${this.config.baseUrl}${endpoint}`;\n\n const headers: HeadersInit = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.config.apiKey}`,\n \"devic-api-source\": \"ui\",\n ...options.headers,\n };\n\n const response = await fetch(url, {\n ...options,\n headers,\n });\n\n if (!response.ok) {\n let errorData: ApiError;\n try {\n errorData = await response.json();\n } catch {\n errorData = {\n statusCode: response.status,\n message: response.statusText,\n };\n }\n throw new DevicApiError(errorData);\n }\n\n // Handle responses that may have a wrapper structure\n const data = await response.json();\n\n // If the response has a data property, extract it (common wrapper pattern)\n if (data && typeof data === \"object\" && \"data\" in data) {\n return data.data as T;\n }\n\n return data as T;\n }\n\n /**\n * Get all assistant specializations\n */\n async getAssistants(external = false): Promise<AssistantSpecialization[]> {\n const query = external ? \"?external=true\" : \"\";\n return this.request<AssistantSpecialization[]>(\n `/api/v1/assistants${query}`,\n );\n }\n\n /**\n * Get a specific assistant specialization\n */\n async getAssistant(identifier: string): Promise<AssistantSpecialization> {\n return this.request<AssistantSpecialization>(\n `/api/v1/assistants/${identifier}`,\n );\n }\n\n /**\n * Send a message to an assistant (sync mode)\n */\n async sendMessage(\n assistantId: string,\n dto: ProcessMessageDto,\n signal?: AbortSignal,\n ): Promise<ChatMessage[]> {\n return this.request<ChatMessage[]>(\n `/api/v1/assistants/${assistantId}/messages${dto.skipSummarization ? \"?skipSummarization=true\" : \"\"}`,\n {\n method: \"POST\",\n body: JSON.stringify(dto),\n signal,\n },\n );\n }\n\n /**\n * Send a message to an assistant (async mode)\n */\n async sendMessageAsync(\n assistantId: string,\n dto: ProcessMessageDto,\n ): Promise<AsyncResponse> {\n return this.request<AsyncResponse>(\n `/api/v1/assistants/${assistantId}/messages?async=true${dto.skipSummarization ? \"&skipSummarization=true\" : \"\"}`,\n {\n method: \"POST\",\n body: JSON.stringify(dto),\n },\n );\n }\n\n /**\n * Get the list of unique tags used across this account's chat histories.\n * Backed by GET /api/v1/assistants/tags. Useful for autocompletion / filters.\n */\n async getChatTags(): Promise<string[]> {\n return this.request<string[]>(`/api/v1/assistants/tags`);\n }\n\n /**\n * Get real-time chat history (for polling in async mode)\n */\n async getRealtimeHistory(\n assistantId: string,\n chatUid: string,\n ): Promise<RealtimeChatHistory> {\n return this.request<RealtimeChatHistory>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/realtime`,\n );\n }\n\n /**\n * Get chat history for a specific conversation\n */\n async getChatHistory(\n assistantId: string,\n chatUid: string,\n options?: { tenantId?: string },\n ): Promise<ChatHistory> {\n const params = new URLSearchParams();\n if (options?.tenantId) {\n params.set(\"tenantId\", options.tenantId);\n }\n const query = params.toString();\n return this.request<ChatHistory>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}${query ? `?${query}` : \"\"}`,\n );\n }\n\n /**\n * List conversations for an assistant\n */\n async listConversations(\n assistantId: string,\n options?: {\n tenantId?: string;\n subtenantId?: string;\n offset?: number;\n limit?: number;\n },\n ): Promise<ListConversationsResponse> {\n const params = new URLSearchParams();\n if (options?.tenantId) {\n params.set(\"tenantId\", options.tenantId);\n }\n if (options?.subtenantId) {\n params.set(\"subtenantId\", options.subtenantId);\n }\n if (options?.offset != null) {\n params.set(\"offset\", String(options.offset));\n }\n if (options?.limit != null) {\n params.set(\"limit\", String(options.limit));\n }\n params.set(\"omitContent\", \"true\");\n const query = params.toString();\n return this.request<ListConversationsResponse>(\n `/api/v1/assistants/${assistantId}/chats${query ? `?${query}` : \"\"}`,\n );\n }\n\n /**\n * Send tool call responses back to the assistant\n */\n async sendToolResponses(\n assistantId: string,\n chatUid: string,\n responses: ToolCallResponse[],\n ): Promise<AsyncResponse> {\n return this.request<AsyncResponse>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/tool-response`,\n {\n method: \"POST\",\n body: JSON.stringify({ responses }),\n },\n );\n }\n\n /**\n * Submit feedback for a chat message\n */\n async submitChatFeedback(\n assistantId: string,\n chatUid: string,\n data: FeedbackSubmission,\n ): Promise<FeedbackEntry> {\n return this.request<FeedbackEntry>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/feedback`,\n {\n method: \"POST\",\n body: JSON.stringify(data),\n },\n );\n }\n\n /**\n * Get all feedback for a chat\n */\n async getChatFeedback(\n assistantId: string,\n chatUid: string,\n ): Promise<FeedbackEntry[]> {\n return this.request<FeedbackEntry[]>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/feedback`,\n );\n }\n\n /**\n * Get an agent thread by ID\n */\n async getThreadById(\n threadId: string,\n withTasks = false,\n ): Promise<AgentThreadDto> {\n const query = withTasks ? \"?withTasks=true\" : \"\";\n return this.request<AgentThreadDto>(\n `/api/v1/agents/threads/${threadId}${query}`,\n );\n }\n\n /**\n * Get agent details\n */\n async getAgentDetails(agentId: string): Promise<AgentDto> {\n return this.request<AgentDto>(`/api/v1/agents/${agentId}`);\n }\n\n /**\n * Get an AI-generated explanation of a thread's execution\n */\n async explainAgentThread(threadId: string): Promise<string> {\n return this.request<string>(\n `/api/v1/agents/threads/${threadId}/explain`,\n );\n }\n\n /**\n * Pause or resume a thread\n */\n async pauseResumeThread(\n threadId: string,\n action: \"paused\" | \"queued\",\n ): Promise<void> {\n return this.request<void>(\n `/api/v1/agents/threads/${threadId}/pause-resume`,\n {\n method: \"POST\",\n body: JSON.stringify({ action }),\n },\n );\n }\n\n /**\n * Handle thread approval (approve/reject)\n */\n async handleThreadApproval(\n threadId: string,\n approved: boolean,\n retry: boolean,\n message: string,\n ): Promise<void> {\n return this.request<void>(\n `/api/v1/agents/threads/${threadId}/approval`,\n {\n method: \"POST\",\n body: JSON.stringify({\n action: approved ? \"approved\" : \"rejected\",\n message,\n retry,\n }),\n },\n );\n }\n\n /**\n * Manually complete a thread\n */\n async completeThread(\n threadId: string,\n completionState: string,\n ): Promise<void> {\n return this.request<void>(\n `/api/v1/agents/threads/${threadId}/complete`,\n {\n method: \"POST\",\n body: JSON.stringify({ state: completionState }),\n },\n );\n }\n\n /**\n * Continue an existing thread with a new user message. The backend decides how\n * to apply it based on the thread state: a finished/failed/waiting thread is\n * re-queued and re-run with the message appended, while a running/queued thread\n * receives it on its next turn (right after the pending tool response). Returns\n * the updated thread.\n */\n async sendThreadMessage(\n threadId: string,\n message: string | Record<string, unknown>,\n ): Promise<AgentThreadDto> {\n return this.request<AgentThreadDto>(\n `/api/v1/agents/threads/${threadId}/messages`,\n {\n method: \"POST\",\n body: JSON.stringify({ message }),\n },\n );\n }\n\n /**\n * Stop an in-progress async chat.\n * The current LLM call or tool execution will finish, then the chat\n * will be marked as completed with the history accumulated so far.\n */\n async stopChat(\n assistantId: string,\n chatUid: string,\n ): Promise<{ chatUid: string; message: string }> {\n return this.request<{ chatUid: string; message: string }>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/stop`,\n { method: \"POST\" },\n );\n }\n\n /**\n * Upload a file and get a download URL\n */\n async uploadFile(\n file: File,\n ): Promise<{ name: string; downloadUrl: string; fileType: string }> {\n const url = `${this.config.baseUrl}/api/v1/files/upload`;\n\n const formData = new FormData();\n formData.append(\"file\", file);\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.config.apiKey}`,\n \"devic-api-source\": \"ui\",\n },\n body: formData,\n });\n\n if (!response.ok) {\n let errorData: { statusCode: number; message: string };\n try {\n errorData = await response.json();\n } catch {\n errorData = {\n statusCode: response.status,\n message: response.statusText,\n };\n }\n throw new DevicApiError(errorData);\n }\n\n const data = await response.json();\n if (data && typeof data === \"object\" && \"data\" in data) {\n return data.data;\n }\n return data;\n }\n\n /**\n * Transcribe audio to text using the /whisper endpoint.\n * Accepts either an audio binary (Blob/File, sent as multipart/form-data) or\n * a download URL string (sent as `audioUrl`). The backend stores the binary\n * and runs speech-to-text with Devic's own OpenAI key. Returns the text and a\n * `transcriptId` to attach to the resulting message.\n */\n async transcribeAudio(\n audio: Blob | string,\n options?: {\n language?: string;\n messageUid?: string;\n chatUid?: string;\n tenantId?: string;\n fileName?: string;\n },\n ): Promise<WhisperTranscriptionResponse> {\n const url = `${this.config.baseUrl}/api/v1/whisper`;\n\n const formData = new FormData();\n if (typeof audio === \"string\") {\n formData.append(\"audioUrl\", audio);\n } else {\n formData.append(\"audio\", audio, options?.fileName || \"recording.webm\");\n }\n if (options?.language) formData.append(\"language\", options.language);\n if (options?.messageUid) formData.append(\"messageUid\", options.messageUid);\n if (options?.chatUid) formData.append(\"chatUid\", options.chatUid);\n if (options?.tenantId) formData.append(\"tenantId\", options.tenantId);\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.config.apiKey}`,\n \"devic-api-source\": \"ui\",\n },\n body: formData,\n });\n\n if (!response.ok) {\n let errorData: { statusCode: number; message: string };\n try {\n errorData = await response.json();\n } catch {\n errorData = {\n statusCode: response.status,\n message: response.statusText,\n };\n }\n throw new DevicApiError(errorData);\n }\n\n const data = await response.json();\n if (data && typeof data === \"object\" && \"data\" in data) {\n return data.data;\n }\n return data;\n }\n\n /**\n * Fetch a single speech-to-text transcript by its id (the `transcriptId`\n * stored on a message). Returns the transcribed text and the download URL of\n * the source audio so the chat can offer playback of a dictated message.\n */\n async getTranscript(\n transcriptId: string,\n ): Promise<WhisperTranscriptionResponse> {\n return this.request<WhisperTranscriptionResponse>(\n `/api/v1/whisper/${encodeURIComponent(transcriptId)}`,\n );\n }\n\n /**\n * Get chat history content (full conversation after handoff)\n */\n async getChatHistoryContent(\n assistantId: string,\n chatUid: string,\n ): Promise<ChatMessage[]> {\n return this.request<ChatMessage[]>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/content`,\n );\n }\n\n /**\n * Get the current usage limits + consumption for a tenant (or a specific\n * subtenant). Read-only — backed by `GET /api/v1/tenant-usage/:tenantId`\n * (or `/:tenantId/subtenants/:subtenantId`), which is part of the devic-ui\n * key preset. Returns the effective rules with their live consumption and the\n * active tier. Use it to render a usage bar.\n */\n async getTenantUsage(\n tenantId: string,\n subtenantId?: string,\n ): Promise<TenantUsage> {\n const path = subtenantId\n ? `/api/v1/tenant-usage/${encodeURIComponent(tenantId)}/subtenants/${encodeURIComponent(subtenantId)}`\n : `/api/v1/tenant-usage/${encodeURIComponent(tenantId)}`;\n return this.request<TenantUsage>(path);\n }\n\n /**\n * Get the durable per-window usage history for a tenant (or subtenant).\n * Read-only — backed by `GET /api/v1/tenant-usage/:tenantId/history`.\n */\n async getTenantUsageHistory(\n tenantId: string,\n options?: TenantUsageHistoryQuery,\n ): Promise<TenantUsageHistoryRow[]> {\n const params = new URLSearchParams();\n if (options?.subtenantId) params.set(\"subtenantId\", options.subtenantId);\n if (options?.scope) params.set(\"scope\", options.scope);\n if (options?.metric) params.set(\"metric\", options.metric);\n if (options?.windowUnit) params.set(\"windowUnit\", options.windowUnit);\n if (options?.from != null) params.set(\"from\", String(options.from));\n if (options?.to != null) params.set(\"to\", String(options.to));\n if (options?.limit != null) params.set(\"limit\", String(options.limit));\n if (options?.skip != null) params.set(\"skip\", String(options.skip));\n const query = params.toString();\n return this.request<TenantUsageHistoryRow[]>(\n `/api/v1/tenant-usage/${encodeURIComponent(tenantId)}/history${query ? `?${query}` : \"\"}`,\n );\n }\n\n private coreMemoryPath(\n assistantId: string,\n tenantId?: string,\n subtenantId?: string,\n entryId?: number,\n ): string {\n const params = new URLSearchParams();\n if (tenantId) params.set(\"tenantId\", tenantId);\n if (subtenantId) params.set(\"subtenantId\", subtenantId);\n const query = params.toString();\n return `/api/v1/memory/assistants/${encodeURIComponent(assistantId)}/core${\n entryId != null ? `/${entryId}` : \"\"\n }${query ? `?${query}` : \"\"}`;\n }\n\n /**\n * Core memory entries of the bucket the assistant resolves for a\n * tenant/subtenant combination — what the assistant permanently remembers\n * there. `enabled: false` when the assistant has no core memory tier.\n */\n async getCoreMemory(\n assistantId: string,\n options?: { tenantId?: string; subtenantId?: string },\n ): Promise<CoreMemoryList> {\n return this.request<CoreMemoryList>(\n this.coreMemoryPath(assistantId, options?.tenantId, options?.subtenantId),\n );\n }\n\n /** Add a standing core memory entry to the assistant's resolved bucket. */\n async addCoreMemoryEntry(\n assistantId: string,\n entry: { content: string; section?: string; pinned?: boolean },\n options?: { tenantId?: string; subtenantId?: string },\n ): Promise<{ entry?: CoreMemoryEntry; deduped: boolean }> {\n return this.request(\n this.coreMemoryPath(assistantId, options?.tenantId, options?.subtenantId),\n { method: \"POST\", body: JSON.stringify(entry) },\n );\n }\n\n /** Edit the text, section or pinned flag of a core memory entry. */\n async updateCoreMemoryEntry(\n assistantId: string,\n entryId: number,\n patch: { content?: string; section?: string; pinned?: boolean },\n options?: { tenantId?: string; subtenantId?: string },\n ): Promise<CoreMemoryEntry> {\n return this.request<CoreMemoryEntry>(\n this.coreMemoryPath(\n assistantId,\n options?.tenantId,\n options?.subtenantId,\n entryId,\n ),\n { method: \"PATCH\", body: JSON.stringify(patch) },\n );\n }\n\n /** Remove (archive) a core memory entry. */\n async deleteCoreMemoryEntry(\n assistantId: string,\n entryId: number,\n options?: { tenantId?: string; subtenantId?: string },\n ): Promise<{ removed: boolean; id?: number }> {\n return this.request(\n this.coreMemoryPath(\n assistantId,\n options?.tenantId,\n options?.subtenantId,\n entryId,\n ),\n { method: \"DELETE\" },\n );\n }\n\n // ── Connected apps of the end user ────────────────────────────────\n //\n // Backed by `/api/v1/tenant-integrations`: the tenant is resolved on the\n // server and never taken from the path. The tenant/subtenant sent here\n // identify the end user in front of the widget, so one tenant's accounts are\n // never reachable from another's.\n\n private integrationsQuery(options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n returnTo?: string;\n }): string {\n const params = new URLSearchParams({ assistantId: options.assistantId });\n if (options.tenantId) params.set(\"tenantId\", options.tenantId);\n if (options.subtenantId) params.set(\"subtenantId\", options.subtenantId);\n if (options.returnTo) params.set(\"returnTo\", options.returnTo);\n return params.toString();\n }\n\n /** Apps this assistant offers, with the end user's own connection status. */\n async getIntegrations(options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n }): Promise<Integration[]> {\n return this.request<Integration[]>(\n `/api/v1/tenant-integrations?${this.integrationsQuery(options)}`,\n );\n }\n\n /**\n * Starts connecting an account. Returns the URL to open in a popup.\n *\n * `returnTo` is where the callback posts the result back to, and the server\n * refuses any value that does not match the origin this request came from —\n * so it cannot be turned into an open redirector.\n */\n async connectIntegration(\n app: string,\n options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n returnTo?: string;\n },\n ): Promise<{ authorizationUrl: string }> {\n return this.request<{ authorizationUrl: string }>(\n `/api/v1/tenant-integrations/${encodeURIComponent(app)}/connect?${this.integrationsQuery(options)}`,\n { method: \"POST\" },\n );\n }\n\n /** Disconnects one of the end user's own accounts. */\n async disconnectIntegration(\n accountId: string,\n options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n },\n ): Promise<{ disconnected: boolean }> {\n return this.request(\n `/api/v1/tenant-integrations/accounts/${encodeURIComponent(accountId)}?${this.integrationsQuery(options)}`,\n { method: \"DELETE\" },\n );\n }\n\n /**\n * Drops the server's short-lived cache of the end user's connections.\n *\n * Called right after the OAuth popup closes: without it the freshly connected\n * app would keep reading as disconnected until the cache expires, which looks\n * like the connection silently failed.\n */\n async refreshIntegrations(options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n }): Promise<{ refreshed: boolean }> {\n return this.request(\n `/api/v1/tenant-integrations/refresh?${this.integrationsQuery(options)}`,\n { method: \"POST\" },\n );\n }\n}\n\n/**\n * Custom error class for API errors\n */\nexport class DevicApiError extends Error {\n public statusCode: number;\n public errorType?: string;\n /** Structured error details (e.g. usage-limit blocking info on a 429). */\n public details?: any;\n\n constructor(error: ApiError) {\n super(error.message);\n this.name = \"DevicApiError\";\n this.statusCode = error.statusCode;\n this.errorType = error.error;\n this.details = error.details;\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sources":["../../../src/api/client.ts"],"sourcesContent":["import type {\n ProcessMessageDto,\n ChatMessage,\n AsyncResponse,\n RealtimeChatHistory,\n ChatHistory,\n AssistantSpecialization,\n ApiError,\n ToolCallResponse,\n ConversationSummary,\n ListConversationsResponse,\n FeedbackSubmission,\n FeedbackEntry,\n AgentThreadDto,\n AgentDto,\n WhisperTranscriptionResponse,\n TenantUsage,\n TenantUsageHistoryRow,\n TenantUsageHistoryQuery,\n CoreMemoryList,\n CoreMemoryEntry,\n Integration,\n} from \"./types\";\n\n/**\n * A tenant session, as the integrator's backend hands it over.\n *\n * A bare string is accepted too — the expiry is then read out of the token\n * itself, so the simplest possible source still gets proactive renewal.\n */\nexport interface TenantSessionToken {\n token: string;\n /** Epoch milliseconds. */\n expiresAt?: number;\n /** Seconds from now. Used when `expiresAt` is absent. */\n expiresIn?: number;\n}\n\nexport interface DevicApiClientConfig {\n /**\n * The public API key. Optional when `getTenantSession` is supplied — a page\n * using tenant sessions has no reason to carry one.\n */\n apiKey?: string;\n baseUrl: string;\n /**\n * Where the tenant session comes from.\n *\n * Supplying this changes what the tenant IS: with an API key alone the tenant\n * is whatever the page says it is, and the page can say anything. With a\n * session it is what your server signed.\n *\n * A function rather than a value because it is called again on its own —\n * before the token expires and after the API rejects one. It does not have to\n * reach your backend: reading a cookie your login already set is a perfectly\n * good answer, and then the whole thing is `async () => readCookie(…)`.\n */\n getTenantSession?: () => Promise<string | TenantSessionToken>;\n /**\n * Called when the session is dead and cannot be replaced — the API rejected\n * it and `getTenantSession` handed back the same expired token.\n *\n * Matters most when the session comes from a cookie with no way to renew it:\n * without this the widget simply stops answering, at the exact moment the\n * user's own login has also expired. Refresh the page, send them to log in,\n * or say something — but say it.\n */\n onSessionExpired?: () => void;\n}\n\n/** Renew this long before expiry, so a request never leaves with a dead token. */\nconst RENEWAL_MARGIN_MS = 60_000;\n\n/**\n * The expiry inside a JWT, in epoch milliseconds.\n *\n * Read rather than required, so the session source can return just the string.\n * Any failure means \"no idea\", and the token is then renewed only when the API\n * rejects it — correct, just less graceful.\n */\nfunction expiryOf(token: string): number | undefined {\n try {\n const payload = token.split(\".\")[1];\n if (!payload) return undefined;\n const json = atob(payload.replace(/-/g, \"+\").replace(/_/g, \"/\"));\n const exp = JSON.parse(json)?.exp;\n return typeof exp === \"number\" ? exp * 1000 : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Devic API client using native fetch\n */\nexport class DevicApiClient {\n private config: DevicApiClientConfig;\n private session?: { token: string; expiresAt?: number };\n /** In flight renewal, shared so a burst of calls fetches one token. */\n private renewing?: Promise<string>;\n /** So a page full of widgets reports one expiry, not one per widget. */\n private expiryReported = false;\n\n constructor(config: DevicApiClientConfig) {\n this.config = config;\n }\n\n /**\n * Update client configuration\n */\n setConfig(config: Partial<DevicApiClientConfig>): void {\n const previous = this.config;\n this.config = { ...this.config, ...config };\n // A new session source speaks for a different end user; keeping the old\n // token would show them the previous one's conversations.\n if (\n config.getTenantSession &&\n config.getTenantSession !== previous.getTenantSession\n ) {\n this.session = undefined;\n this.expiryReported = false;\n }\n }\n\n /** The credential for the next request, renewed if it is about to expire. */\n private async authorization(force = false): Promise<string> {\n if (!this.config.getTenantSession) return this.config.apiKey ?? \"\";\n\n const current = this.session;\n const stillGood =\n current &&\n (current.expiresAt === undefined ||\n current.expiresAt - Date.now() > RENEWAL_MARGIN_MS);\n if (stillGood && !force) return current.token;\n\n return this.renew();\n }\n\n private renew(): Promise<string> {\n if (!this.renewing) {\n this.renewing = Promise.resolve(this.config.getTenantSession!())\n .then((result) => {\n const token = typeof result === \"string\" ? result : result.token;\n const declared =\n typeof result === \"string\"\n ? undefined\n : (result.expiresAt ??\n (result.expiresIn\n ? Date.now() + result.expiresIn * 1000\n : undefined));\n this.session = { token, expiresAt: declared ?? expiryOf(token) };\n return token;\n })\n .finally(() => {\n this.renewing = undefined;\n });\n }\n return this.renewing;\n }\n\n /**\n * Whether a rejected request is worth retrying, having got a live session.\n *\n * Takes the token the request actually went out with, not the current one:\n * with several requests in flight another may already have replaced it, and\n * comparing against the current one would read that success as a failure.\n *\n * False means the session is dead and cannot be replaced — a cookie set at\n * login, now expired, with nowhere to renew it from. That is worth telling\n * the host application about, once.\n */\n private async recoverSession(rejected: string): Promise<boolean> {\n if (this.session && this.session.token !== rejected) {\n this.expiryReported = false;\n return true;\n }\n\n let fresh: string | undefined;\n try {\n fresh = await this.renew();\n } catch {\n fresh = undefined;\n }\n if (fresh && fresh !== rejected) {\n this.expiryReported = false;\n return true;\n }\n\n if (!this.expiryReported) {\n this.expiryReported = true;\n this.config.onSessionExpired?.();\n }\n return false;\n }\n\n /**\n * Make an authenticated request to the API\n */\n private async request<T>(\n endpoint: string,\n options: RequestInit = {},\n isRetry = false,\n ): Promise<T> {\n const url = `${this.config.baseUrl}${endpoint}`;\n const credential = await this.authorization();\n\n const headers: HeadersInit = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${credential}`,\n \"devic-api-source\": \"ui\",\n ...options.headers,\n };\n\n const response = await fetch(url, {\n ...options,\n headers,\n });\n\n // A session can die between being checked and being used — a clock adrift,\n // a tab asleep for an hour, the key revoked. One retry with a fresh token\n // turns that into a pause instead of a broken conversation.\n if (response.status === 401 && this.config.getTenantSession && !isRetry) {\n if (await this.recoverSession(credential)) {\n return this.request<T>(endpoint, options, true);\n }\n }\n\n if (!response.ok) {\n let errorData: ApiError;\n try {\n errorData = await response.json();\n } catch {\n errorData = {\n statusCode: response.status,\n message: response.statusText,\n };\n }\n throw new DevicApiError(errorData);\n }\n\n // Handle responses that may have a wrapper structure\n const data = await response.json();\n\n // If the response has a data property, extract it (common wrapper pattern)\n if (data && typeof data === \"object\" && \"data\" in data) {\n return data.data as T;\n }\n\n return data as T;\n }\n\n /**\n * Get all assistant specializations\n */\n async getAssistants(external = false): Promise<AssistantSpecialization[]> {\n const query = external ? \"?external=true\" : \"\";\n return this.request<AssistantSpecialization[]>(\n `/api/v1/assistants${query}`,\n );\n }\n\n /**\n * Get a specific assistant specialization\n */\n async getAssistant(identifier: string): Promise<AssistantSpecialization> {\n return this.request<AssistantSpecialization>(\n `/api/v1/assistants/${identifier}`,\n );\n }\n\n /**\n * Send a message to an assistant (sync mode)\n */\n async sendMessage(\n assistantId: string,\n dto: ProcessMessageDto,\n signal?: AbortSignal,\n ): Promise<ChatMessage[]> {\n return this.request<ChatMessage[]>(\n `/api/v1/assistants/${assistantId}/messages${dto.skipSummarization ? \"?skipSummarization=true\" : \"\"}`,\n {\n method: \"POST\",\n body: JSON.stringify(dto),\n signal,\n },\n );\n }\n\n /**\n * Send a message to an assistant (async mode)\n */\n async sendMessageAsync(\n assistantId: string,\n dto: ProcessMessageDto,\n ): Promise<AsyncResponse> {\n return this.request<AsyncResponse>(\n `/api/v1/assistants/${assistantId}/messages?async=true${dto.skipSummarization ? \"&skipSummarization=true\" : \"\"}`,\n {\n method: \"POST\",\n body: JSON.stringify(dto),\n },\n );\n }\n\n /**\n * Get the list of unique tags used across this account's chat histories.\n * Backed by GET /api/v1/assistants/tags. Useful for autocompletion / filters.\n */\n async getChatTags(): Promise<string[]> {\n return this.request<string[]>(`/api/v1/assistants/tags`);\n }\n\n /**\n * Get real-time chat history (for polling in async mode)\n */\n async getRealtimeHistory(\n assistantId: string,\n chatUid: string,\n ): Promise<RealtimeChatHistory> {\n return this.request<RealtimeChatHistory>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/realtime`,\n );\n }\n\n /**\n * Get chat history for a specific conversation\n */\n async getChatHistory(\n assistantId: string,\n chatUid: string,\n options?: { tenantId?: string },\n ): Promise<ChatHistory> {\n const params = new URLSearchParams();\n if (options?.tenantId) {\n params.set(\"tenantId\", options.tenantId);\n }\n const query = params.toString();\n return this.request<ChatHistory>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}${query ? `?${query}` : \"\"}`,\n );\n }\n\n /**\n * List conversations for an assistant\n */\n async listConversations(\n assistantId: string,\n options?: {\n tenantId?: string;\n subtenantId?: string;\n offset?: number;\n limit?: number;\n },\n ): Promise<ListConversationsResponse> {\n const params = new URLSearchParams();\n if (options?.tenantId) {\n params.set(\"tenantId\", options.tenantId);\n }\n if (options?.subtenantId) {\n params.set(\"subtenantId\", options.subtenantId);\n }\n if (options?.offset != null) {\n params.set(\"offset\", String(options.offset));\n }\n if (options?.limit != null) {\n params.set(\"limit\", String(options.limit));\n }\n params.set(\"omitContent\", \"true\");\n const query = params.toString();\n return this.request<ListConversationsResponse>(\n `/api/v1/assistants/${assistantId}/chats${query ? `?${query}` : \"\"}`,\n );\n }\n\n /**\n * Send tool call responses back to the assistant\n */\n async sendToolResponses(\n assistantId: string,\n chatUid: string,\n responses: ToolCallResponse[],\n ): Promise<AsyncResponse> {\n return this.request<AsyncResponse>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/tool-response`,\n {\n method: \"POST\",\n body: JSON.stringify({ responses }),\n },\n );\n }\n\n /**\n * Submit feedback for a chat message\n */\n async submitChatFeedback(\n assistantId: string,\n chatUid: string,\n data: FeedbackSubmission,\n ): Promise<FeedbackEntry> {\n return this.request<FeedbackEntry>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/feedback`,\n {\n method: \"POST\",\n body: JSON.stringify(data),\n },\n );\n }\n\n /**\n * Get all feedback for a chat\n */\n async getChatFeedback(\n assistantId: string,\n chatUid: string,\n ): Promise<FeedbackEntry[]> {\n return this.request<FeedbackEntry[]>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/feedback`,\n );\n }\n\n /**\n * Get an agent thread by ID\n */\n async getThreadById(\n threadId: string,\n withTasks = false,\n ): Promise<AgentThreadDto> {\n const query = withTasks ? \"?withTasks=true\" : \"\";\n return this.request<AgentThreadDto>(\n `/api/v1/agents/threads/${threadId}${query}`,\n );\n }\n\n /**\n * Get agent details\n */\n async getAgentDetails(agentId: string): Promise<AgentDto> {\n return this.request<AgentDto>(`/api/v1/agents/${agentId}`);\n }\n\n /**\n * Get an AI-generated explanation of a thread's execution\n */\n async explainAgentThread(threadId: string): Promise<string> {\n return this.request<string>(\n `/api/v1/agents/threads/${threadId}/explain`,\n );\n }\n\n /**\n * Pause or resume a thread\n */\n async pauseResumeThread(\n threadId: string,\n action: \"paused\" | \"queued\",\n ): Promise<void> {\n return this.request<void>(\n `/api/v1/agents/threads/${threadId}/pause-resume`,\n {\n method: \"POST\",\n body: JSON.stringify({ action }),\n },\n );\n }\n\n /**\n * Handle thread approval (approve/reject)\n */\n async handleThreadApproval(\n threadId: string,\n approved: boolean,\n retry: boolean,\n message: string,\n ): Promise<void> {\n return this.request<void>(\n `/api/v1/agents/threads/${threadId}/approval`,\n {\n method: \"POST\",\n body: JSON.stringify({\n action: approved ? \"approved\" : \"rejected\",\n message,\n retry,\n }),\n },\n );\n }\n\n /**\n * Manually complete a thread\n */\n async completeThread(\n threadId: string,\n completionState: string,\n ): Promise<void> {\n return this.request<void>(\n `/api/v1/agents/threads/${threadId}/complete`,\n {\n method: \"POST\",\n body: JSON.stringify({ state: completionState }),\n },\n );\n }\n\n /**\n * Continue an existing thread with a new user message. The backend decides how\n * to apply it based on the thread state: a finished/failed/waiting thread is\n * re-queued and re-run with the message appended, while a running/queued thread\n * receives it on its next turn (right after the pending tool response). Returns\n * the updated thread.\n */\n async sendThreadMessage(\n threadId: string,\n message: string | Record<string, unknown>,\n ): Promise<AgentThreadDto> {\n return this.request<AgentThreadDto>(\n `/api/v1/agents/threads/${threadId}/messages`,\n {\n method: \"POST\",\n body: JSON.stringify({ message }),\n },\n );\n }\n\n /**\n * Stop an in-progress async chat.\n * The current LLM call or tool execution will finish, then the chat\n * will be marked as completed with the history accumulated so far.\n */\n async stopChat(\n assistantId: string,\n chatUid: string,\n ): Promise<{ chatUid: string; message: string }> {\n return this.request<{ chatUid: string; message: string }>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/stop`,\n { method: \"POST\" },\n );\n }\n\n /**\n * Upload a file and get a download URL\n */\n async uploadFile(\n file: File,\n isRetry = false,\n ): Promise<{ name: string; downloadUrl: string; fileType: string }> {\n const url = `${this.config.baseUrl}/api/v1/files/upload`;\n\n const formData = new FormData();\n formData.append(\"file\", file);\n\n const credential = await this.authorization();\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${credential}`,\n \"devic-api-source\": \"ui\",\n },\n body: formData,\n });\n\n // The FormData is rebuilt from `file` on the way back in, so unlike a\n // consumed stream this retry is safe.\n if (response.status === 401 && this.config.getTenantSession && !isRetry) {\n if (await this.recoverSession(credential)) return this.uploadFile(file, true);\n }\n\n if (!response.ok) {\n let errorData: { statusCode: number; message: string };\n try {\n errorData = await response.json();\n } catch {\n errorData = {\n statusCode: response.status,\n message: response.statusText,\n };\n }\n throw new DevicApiError(errorData);\n }\n\n const data = await response.json();\n if (data && typeof data === \"object\" && \"data\" in data) {\n return data.data;\n }\n return data;\n }\n\n /**\n * Transcribe audio to text using the /whisper endpoint.\n * Accepts either an audio binary (Blob/File, sent as multipart/form-data) or\n * a download URL string (sent as `audioUrl`). The backend stores the binary\n * and runs speech-to-text with Devic's own OpenAI key. Returns the text and a\n * `transcriptId` to attach to the resulting message.\n */\n async transcribeAudio(\n audio: Blob | string,\n options?: {\n language?: string;\n messageUid?: string;\n chatUid?: string;\n tenantId?: string;\n fileName?: string;\n },\n isRetry = false,\n ): Promise<WhisperTranscriptionResponse> {\n const url = `${this.config.baseUrl}/api/v1/whisper`;\n\n const formData = new FormData();\n if (typeof audio === \"string\") {\n formData.append(\"audioUrl\", audio);\n } else {\n formData.append(\"audio\", audio, options?.fileName || \"recording.webm\");\n }\n if (options?.language) formData.append(\"language\", options.language);\n if (options?.messageUid) formData.append(\"messageUid\", options.messageUid);\n if (options?.chatUid) formData.append(\"chatUid\", options.chatUid);\n if (options?.tenantId) formData.append(\"tenantId\", options.tenantId);\n\n const credential = await this.authorization();\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${credential}`,\n \"devic-api-source\": \"ui\",\n },\n body: formData,\n });\n\n if (response.status === 401 && this.config.getTenantSession && !isRetry) {\n if (await this.recoverSession(credential)) {\n return this.transcribeAudio(audio, options, true);\n }\n }\n\n if (!response.ok) {\n let errorData: { statusCode: number; message: string };\n try {\n errorData = await response.json();\n } catch {\n errorData = {\n statusCode: response.status,\n message: response.statusText,\n };\n }\n throw new DevicApiError(errorData);\n }\n\n const data = await response.json();\n if (data && typeof data === \"object\" && \"data\" in data) {\n return data.data;\n }\n return data;\n }\n\n /**\n * Fetch a single speech-to-text transcript by its id (the `transcriptId`\n * stored on a message). Returns the transcribed text and the download URL of\n * the source audio so the chat can offer playback of a dictated message.\n */\n async getTranscript(\n transcriptId: string,\n ): Promise<WhisperTranscriptionResponse> {\n return this.request<WhisperTranscriptionResponse>(\n `/api/v1/whisper/${encodeURIComponent(transcriptId)}`,\n );\n }\n\n /**\n * Get chat history content (full conversation after handoff)\n */\n async getChatHistoryContent(\n assistantId: string,\n chatUid: string,\n ): Promise<ChatMessage[]> {\n return this.request<ChatMessage[]>(\n `/api/v1/assistants/${assistantId}/chats/${chatUid}/content`,\n );\n }\n\n /**\n * Get the current usage limits + consumption for a tenant (or a specific\n * subtenant). Read-only — backed by `GET /api/v1/tenant-usage/:tenantId`\n * (or `/:tenantId/subtenants/:subtenantId`), which is part of the devic-ui\n * key preset. Returns the effective rules with their live consumption and the\n * active tier. Use it to render a usage bar.\n */\n async getTenantUsage(\n tenantId: string,\n subtenantId?: string,\n ): Promise<TenantUsage> {\n const path = subtenantId\n ? `/api/v1/tenant-usage/${encodeURIComponent(tenantId)}/subtenants/${encodeURIComponent(subtenantId)}`\n : `/api/v1/tenant-usage/${encodeURIComponent(tenantId)}`;\n return this.request<TenantUsage>(path);\n }\n\n /**\n * Get the durable per-window usage history for a tenant (or subtenant).\n * Read-only — backed by `GET /api/v1/tenant-usage/:tenantId/history`.\n */\n async getTenantUsageHistory(\n tenantId: string,\n options?: TenantUsageHistoryQuery,\n ): Promise<TenantUsageHistoryRow[]> {\n const params = new URLSearchParams();\n if (options?.subtenantId) params.set(\"subtenantId\", options.subtenantId);\n if (options?.scope) params.set(\"scope\", options.scope);\n if (options?.metric) params.set(\"metric\", options.metric);\n if (options?.windowUnit) params.set(\"windowUnit\", options.windowUnit);\n if (options?.from != null) params.set(\"from\", String(options.from));\n if (options?.to != null) params.set(\"to\", String(options.to));\n if (options?.limit != null) params.set(\"limit\", String(options.limit));\n if (options?.skip != null) params.set(\"skip\", String(options.skip));\n const query = params.toString();\n return this.request<TenantUsageHistoryRow[]>(\n `/api/v1/tenant-usage/${encodeURIComponent(tenantId)}/history${query ? `?${query}` : \"\"}`,\n );\n }\n\n private coreMemoryPath(\n assistantId: string,\n tenantId?: string,\n subtenantId?: string,\n entryId?: number,\n ): string {\n const params = new URLSearchParams();\n if (tenantId) params.set(\"tenantId\", tenantId);\n if (subtenantId) params.set(\"subtenantId\", subtenantId);\n const query = params.toString();\n return `/api/v1/memory/assistants/${encodeURIComponent(assistantId)}/core${\n entryId != null ? `/${entryId}` : \"\"\n }${query ? `?${query}` : \"\"}`;\n }\n\n /**\n * Core memory entries of the bucket the assistant resolves for a\n * tenant/subtenant combination — what the assistant permanently remembers\n * there. `enabled: false` when the assistant has no core memory tier.\n */\n async getCoreMemory(\n assistantId: string,\n options?: { tenantId?: string; subtenantId?: string },\n ): Promise<CoreMemoryList> {\n return this.request<CoreMemoryList>(\n this.coreMemoryPath(assistantId, options?.tenantId, options?.subtenantId),\n );\n }\n\n /** Add a standing core memory entry to the assistant's resolved bucket. */\n async addCoreMemoryEntry(\n assistantId: string,\n entry: { content: string; section?: string; pinned?: boolean },\n options?: { tenantId?: string; subtenantId?: string },\n ): Promise<{ entry?: CoreMemoryEntry; deduped: boolean }> {\n return this.request(\n this.coreMemoryPath(assistantId, options?.tenantId, options?.subtenantId),\n { method: \"POST\", body: JSON.stringify(entry) },\n );\n }\n\n /** Edit the text, section or pinned flag of a core memory entry. */\n async updateCoreMemoryEntry(\n assistantId: string,\n entryId: number,\n patch: { content?: string; section?: string; pinned?: boolean },\n options?: { tenantId?: string; subtenantId?: string },\n ): Promise<CoreMemoryEntry> {\n return this.request<CoreMemoryEntry>(\n this.coreMemoryPath(\n assistantId,\n options?.tenantId,\n options?.subtenantId,\n entryId,\n ),\n { method: \"PATCH\", body: JSON.stringify(patch) },\n );\n }\n\n /** Remove (archive) a core memory entry. */\n async deleteCoreMemoryEntry(\n assistantId: string,\n entryId: number,\n options?: { tenantId?: string; subtenantId?: string },\n ): Promise<{ removed: boolean; id?: number }> {\n return this.request(\n this.coreMemoryPath(\n assistantId,\n options?.tenantId,\n options?.subtenantId,\n entryId,\n ),\n { method: \"DELETE\" },\n );\n }\n\n // ── Connected apps of the end user ────────────────────────────────\n //\n // Backed by `/api/v1/tenant-integrations`: the tenant is resolved on the\n // server and never taken from the path. The tenant/subtenant sent here\n // identify the end user in front of the widget, so one tenant's accounts are\n // never reachable from another's.\n\n private integrationsQuery(options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n returnTo?: string;\n }): string {\n const params = new URLSearchParams({ assistantId: options.assistantId });\n if (options.tenantId) params.set(\"tenantId\", options.tenantId);\n if (options.subtenantId) params.set(\"subtenantId\", options.subtenantId);\n if (options.returnTo) params.set(\"returnTo\", options.returnTo);\n return params.toString();\n }\n\n /** Apps this assistant offers, with the end user's own connection status. */\n async getIntegrations(options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n }): Promise<Integration[]> {\n return this.request<Integration[]>(\n `/api/v1/tenant-integrations?${this.integrationsQuery(options)}`,\n );\n }\n\n /**\n * Starts connecting an account. Returns the URL to open in a popup.\n *\n * `returnTo` is where the callback posts the result back to, and the server\n * refuses any value that does not match the origin this request came from —\n * so it cannot be turned into an open redirector.\n */\n async connectIntegration(\n app: string,\n options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n returnTo?: string;\n },\n ): Promise<{ authorizationUrl: string }> {\n return this.request<{ authorizationUrl: string }>(\n `/api/v1/tenant-integrations/${encodeURIComponent(app)}/connect?${this.integrationsQuery(options)}`,\n { method: \"POST\" },\n );\n }\n\n /** Disconnects one of the end user's own accounts. */\n async disconnectIntegration(\n accountId: string,\n options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n },\n ): Promise<{ disconnected: boolean }> {\n return this.request(\n `/api/v1/tenant-integrations/accounts/${encodeURIComponent(accountId)}?${this.integrationsQuery(options)}`,\n { method: \"DELETE\" },\n );\n }\n\n /**\n * Drops the server's short-lived cache of the end user's connections.\n *\n * Called right after the OAuth popup closes: without it the freshly connected\n * app would keep reading as disconnected until the cache expires, which looks\n * like the connection silently failed.\n */\n async refreshIntegrations(options: {\n assistantId: string;\n tenantId?: string;\n subtenantId?: string;\n }): Promise<{ refreshed: boolean }> {\n return this.request(\n `/api/v1/tenant-integrations/refresh?${this.integrationsQuery(options)}`,\n { method: \"POST\" },\n );\n }\n}\n\n/**\n * Custom error class for API errors\n */\nexport class DevicApiError extends Error {\n public statusCode: number;\n public errorType?: string;\n /** Structured error details (e.g. usage-limit blocking info on a 429). */\n public details?: any;\n\n constructor(error: ApiError) {\n super(error.message);\n this.name = \"DevicApiError\";\n this.statusCode = error.statusCode;\n this.errorType = error.error;\n this.details = error.details;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -133,13 +133,15 @@ const AICommandBar = forwardRef(function AICommandBar(props, ref) {
133
133
  const resolvedBaseUrl = baseUrl || context?.baseUrl || 'https://api.devic.ai';
134
134
  // Initialize feedback client
135
135
  useEffect(() => {
136
- if (resolvedApiKey && !feedbackClientRef.current) {
136
+ if ((resolvedApiKey || context?.getTenantSession) && !feedbackClientRef.current) {
137
137
  feedbackClientRef.current = new DevicApiClient({
138
138
  apiKey: resolvedApiKey,
139
139
  baseUrl: resolvedBaseUrl,
140
+ getTenantSession: context?.getTenantSession,
141
+ onSessionExpired: context?.onSessionExpired,
140
142
  });
141
143
  }
142
- }, [resolvedApiKey, resolvedBaseUrl]);
144
+ }, [resolvedApiKey, context?.getTenantSession, resolvedBaseUrl]);
143
145
  // Reset feedback state when result changes
144
146
  useEffect(() => {
145
147
  if (hook.result) {