@informedai/react 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +46 -43
- package/dist/index.d.ts +46 -43
- package/dist/index.js +126 -158
- package/dist/index.mjs +126 -157
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -14,11 +14,12 @@ interface Session {
|
|
|
14
14
|
}
|
|
15
15
|
interface WidgetMessage {
|
|
16
16
|
id: string;
|
|
17
|
-
role: 'user' | 'assistant' | 'system';
|
|
17
|
+
role: 'user' | 'assistant' | 'agent' | 'system';
|
|
18
18
|
content: string;
|
|
19
|
-
type: 'text' | 'quick_actions' | 'task_intro' | 'pending_preview';
|
|
19
|
+
type: 'text' | 'quick_actions' | 'task_intro' | 'pending_preview' | 'scripted' | 'ai_response' | 'user_input' | 'quick_action';
|
|
20
20
|
quickActions?: QuickAction[];
|
|
21
21
|
timestamp: string;
|
|
22
|
+
taskContext?: string;
|
|
22
23
|
}
|
|
23
24
|
interface QuickAction {
|
|
24
25
|
id: string;
|
|
@@ -71,12 +72,10 @@ interface Document {
|
|
|
71
72
|
};
|
|
72
73
|
}
|
|
73
74
|
interface InformedAssistantConfig {
|
|
74
|
-
/**
|
|
75
|
-
|
|
75
|
+
/** Document Type ID - identifies which form schema to use */
|
|
76
|
+
documentTypeId: string;
|
|
76
77
|
/** API base URL (defaults to https://api.informedassistant.ai/api/v1) */
|
|
77
78
|
apiUrl?: string;
|
|
78
|
-
/** Document ID to work with */
|
|
79
|
-
documentId: string;
|
|
80
79
|
/** Optional: Existing session ID to resume */
|
|
81
80
|
sessionId?: string;
|
|
82
81
|
/** Callback when a field value is applied */
|
|
@@ -119,14 +118,6 @@ interface UseSessionReturn {
|
|
|
119
118
|
applyPendingValue: () => Promise<void>;
|
|
120
119
|
skipTask: () => Promise<void>;
|
|
121
120
|
}
|
|
122
|
-
interface UseDocumentReturn {
|
|
123
|
-
document: Document | null;
|
|
124
|
-
documentType: DocumentType | null;
|
|
125
|
-
isLoading: boolean;
|
|
126
|
-
error: Error | null;
|
|
127
|
-
updateField: (fieldName: string, value: unknown) => Promise<void>;
|
|
128
|
-
refetch: () => Promise<void>;
|
|
129
|
-
}
|
|
130
121
|
|
|
131
122
|
interface InformedAssistantProps extends InformedAssistantConfig {
|
|
132
123
|
/** Additional CSS class name */
|
|
@@ -173,62 +164,74 @@ declare function InformedAIProvider({ config, children }: InformedAIProviderProp
|
|
|
173
164
|
*/
|
|
174
165
|
|
|
175
166
|
interface UseSessionOptions {
|
|
176
|
-
|
|
167
|
+
/** Document Type ID - identifies which form schema to use */
|
|
168
|
+
documentTypeId: string;
|
|
169
|
+
/** API base URL (defaults to https://api.informedassistant.ai/api/v1) */
|
|
177
170
|
apiUrl?: string;
|
|
178
|
-
|
|
171
|
+
/** Optional: Existing session ID to resume */
|
|
179
172
|
sessionId?: string;
|
|
173
|
+
/** Callback when session state changes */
|
|
180
174
|
onSessionChange?: (session: Session) => void;
|
|
175
|
+
/** Callback when an error occurs */
|
|
181
176
|
onError?: (error: Error) => void;
|
|
182
177
|
}
|
|
183
178
|
declare function useSession(options: UseSessionOptions): UseSessionReturn;
|
|
184
179
|
|
|
185
|
-
/**
|
|
186
|
-
* useDocument Hook
|
|
187
|
-
* For developers who want direct access to document management
|
|
188
|
-
*/
|
|
189
|
-
|
|
190
|
-
interface UseDocumentOptions {
|
|
191
|
-
apiKey: string;
|
|
192
|
-
apiUrl?: string;
|
|
193
|
-
documentId: string;
|
|
194
|
-
onError?: (error: Error) => void;
|
|
195
|
-
}
|
|
196
|
-
declare function useDocument(options: UseDocumentOptions): UseDocumentReturn;
|
|
197
|
-
|
|
198
180
|
/**
|
|
199
181
|
* InformedAI API Client
|
|
200
182
|
* Handles all communication with the InformedAI backend
|
|
183
|
+
*
|
|
184
|
+
* Uses keyless widget endpoints with domain-based authentication.
|
|
201
185
|
*/
|
|
202
186
|
|
|
187
|
+
interface CreateSessionResponse {
|
|
188
|
+
session: Session;
|
|
189
|
+
document: Document;
|
|
190
|
+
documentType: {
|
|
191
|
+
id: string;
|
|
192
|
+
name: string;
|
|
193
|
+
displayName: string;
|
|
194
|
+
schema: unknown;
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
interface ApplyResponse {
|
|
198
|
+
session: Session;
|
|
199
|
+
appliedField: string;
|
|
200
|
+
appliedValue: unknown;
|
|
201
|
+
}
|
|
203
202
|
declare class InformedAIClient {
|
|
204
|
-
private apiKey;
|
|
205
203
|
private apiUrl;
|
|
206
|
-
constructor(
|
|
204
|
+
constructor(apiUrl?: string);
|
|
207
205
|
private getHeaders;
|
|
208
206
|
private request;
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
207
|
+
/**
|
|
208
|
+
* Create a new session for a document type.
|
|
209
|
+
* This automatically creates a document with default values.
|
|
210
|
+
*/
|
|
211
|
+
createSession(documentTypeId: string): Promise<CreateSessionResponse>;
|
|
212
|
+
/**
|
|
213
|
+
* Get an existing session.
|
|
214
|
+
*/
|
|
213
215
|
getSession(id: string): Promise<Session>;
|
|
214
|
-
deleteSession(id: string): Promise<void>;
|
|
215
216
|
/**
|
|
216
|
-
* Send a message to the session with SSE streaming
|
|
217
|
+
* Send a message to the session with SSE streaming.
|
|
217
218
|
*/
|
|
218
219
|
sendMessage(sessionId: string, message: string, onEvent: (event: SSEEvent) => void): Promise<void>;
|
|
219
220
|
/**
|
|
220
|
-
* Send a quick action to the session
|
|
221
|
+
* Send a quick action to the session.
|
|
222
|
+
* For actions that trigger AI (task_action:*), returns SSE stream.
|
|
223
|
+
* For other actions (select_task:*, resume_task:*), returns session directly.
|
|
221
224
|
*/
|
|
222
|
-
sendQuickAction(sessionId: string, action: string,
|
|
225
|
+
sendQuickAction(sessionId: string, action: string, onEvent?: (event: SSEEvent) => void): Promise<Session>;
|
|
223
226
|
/**
|
|
224
|
-
* Apply the pending value for the active task
|
|
227
|
+
* Apply the pending value for the active task.
|
|
225
228
|
*/
|
|
226
|
-
applyPendingValue(sessionId: string): Promise<
|
|
229
|
+
applyPendingValue(sessionId: string): Promise<ApplyResponse>;
|
|
227
230
|
/**
|
|
228
|
-
* Skip the active task
|
|
231
|
+
* Skip the active task.
|
|
229
232
|
*/
|
|
230
233
|
skipTask(sessionId: string): Promise<Session>;
|
|
231
234
|
private processSSEStream;
|
|
232
235
|
}
|
|
233
236
|
|
|
234
|
-
export { type ChatMessage, type Document, type DocumentType, type DocumentTypeSchema, type FieldDefinition, InformedAIClient, InformedAIProvider, InformedAssistant, type InformedAssistantConfig, type QuickAction, type SSEEvent, type Session, type TaskConfig, type TaskState, type
|
|
237
|
+
export { type ChatMessage, type Document, type DocumentType, type DocumentTypeSchema, type FieldDefinition, InformedAIClient, InformedAIProvider, InformedAssistant, type InformedAssistantConfig, type QuickAction, type SSEEvent, type Session, type TaskConfig, type TaskState, type UseSessionReturn, type WidgetMessage, type WidgetTheme, useInformedAI, useSession };
|
package/dist/index.d.ts
CHANGED
|
@@ -14,11 +14,12 @@ interface Session {
|
|
|
14
14
|
}
|
|
15
15
|
interface WidgetMessage {
|
|
16
16
|
id: string;
|
|
17
|
-
role: 'user' | 'assistant' | 'system';
|
|
17
|
+
role: 'user' | 'assistant' | 'agent' | 'system';
|
|
18
18
|
content: string;
|
|
19
|
-
type: 'text' | 'quick_actions' | 'task_intro' | 'pending_preview';
|
|
19
|
+
type: 'text' | 'quick_actions' | 'task_intro' | 'pending_preview' | 'scripted' | 'ai_response' | 'user_input' | 'quick_action';
|
|
20
20
|
quickActions?: QuickAction[];
|
|
21
21
|
timestamp: string;
|
|
22
|
+
taskContext?: string;
|
|
22
23
|
}
|
|
23
24
|
interface QuickAction {
|
|
24
25
|
id: string;
|
|
@@ -71,12 +72,10 @@ interface Document {
|
|
|
71
72
|
};
|
|
72
73
|
}
|
|
73
74
|
interface InformedAssistantConfig {
|
|
74
|
-
/**
|
|
75
|
-
|
|
75
|
+
/** Document Type ID - identifies which form schema to use */
|
|
76
|
+
documentTypeId: string;
|
|
76
77
|
/** API base URL (defaults to https://api.informedassistant.ai/api/v1) */
|
|
77
78
|
apiUrl?: string;
|
|
78
|
-
/** Document ID to work with */
|
|
79
|
-
documentId: string;
|
|
80
79
|
/** Optional: Existing session ID to resume */
|
|
81
80
|
sessionId?: string;
|
|
82
81
|
/** Callback when a field value is applied */
|
|
@@ -119,14 +118,6 @@ interface UseSessionReturn {
|
|
|
119
118
|
applyPendingValue: () => Promise<void>;
|
|
120
119
|
skipTask: () => Promise<void>;
|
|
121
120
|
}
|
|
122
|
-
interface UseDocumentReturn {
|
|
123
|
-
document: Document | null;
|
|
124
|
-
documentType: DocumentType | null;
|
|
125
|
-
isLoading: boolean;
|
|
126
|
-
error: Error | null;
|
|
127
|
-
updateField: (fieldName: string, value: unknown) => Promise<void>;
|
|
128
|
-
refetch: () => Promise<void>;
|
|
129
|
-
}
|
|
130
121
|
|
|
131
122
|
interface InformedAssistantProps extends InformedAssistantConfig {
|
|
132
123
|
/** Additional CSS class name */
|
|
@@ -173,62 +164,74 @@ declare function InformedAIProvider({ config, children }: InformedAIProviderProp
|
|
|
173
164
|
*/
|
|
174
165
|
|
|
175
166
|
interface UseSessionOptions {
|
|
176
|
-
|
|
167
|
+
/** Document Type ID - identifies which form schema to use */
|
|
168
|
+
documentTypeId: string;
|
|
169
|
+
/** API base URL (defaults to https://api.informedassistant.ai/api/v1) */
|
|
177
170
|
apiUrl?: string;
|
|
178
|
-
|
|
171
|
+
/** Optional: Existing session ID to resume */
|
|
179
172
|
sessionId?: string;
|
|
173
|
+
/** Callback when session state changes */
|
|
180
174
|
onSessionChange?: (session: Session) => void;
|
|
175
|
+
/** Callback when an error occurs */
|
|
181
176
|
onError?: (error: Error) => void;
|
|
182
177
|
}
|
|
183
178
|
declare function useSession(options: UseSessionOptions): UseSessionReturn;
|
|
184
179
|
|
|
185
|
-
/**
|
|
186
|
-
* useDocument Hook
|
|
187
|
-
* For developers who want direct access to document management
|
|
188
|
-
*/
|
|
189
|
-
|
|
190
|
-
interface UseDocumentOptions {
|
|
191
|
-
apiKey: string;
|
|
192
|
-
apiUrl?: string;
|
|
193
|
-
documentId: string;
|
|
194
|
-
onError?: (error: Error) => void;
|
|
195
|
-
}
|
|
196
|
-
declare function useDocument(options: UseDocumentOptions): UseDocumentReturn;
|
|
197
|
-
|
|
198
180
|
/**
|
|
199
181
|
* InformedAI API Client
|
|
200
182
|
* Handles all communication with the InformedAI backend
|
|
183
|
+
*
|
|
184
|
+
* Uses keyless widget endpoints with domain-based authentication.
|
|
201
185
|
*/
|
|
202
186
|
|
|
187
|
+
interface CreateSessionResponse {
|
|
188
|
+
session: Session;
|
|
189
|
+
document: Document;
|
|
190
|
+
documentType: {
|
|
191
|
+
id: string;
|
|
192
|
+
name: string;
|
|
193
|
+
displayName: string;
|
|
194
|
+
schema: unknown;
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
interface ApplyResponse {
|
|
198
|
+
session: Session;
|
|
199
|
+
appliedField: string;
|
|
200
|
+
appliedValue: unknown;
|
|
201
|
+
}
|
|
203
202
|
declare class InformedAIClient {
|
|
204
|
-
private apiKey;
|
|
205
203
|
private apiUrl;
|
|
206
|
-
constructor(
|
|
204
|
+
constructor(apiUrl?: string);
|
|
207
205
|
private getHeaders;
|
|
208
206
|
private request;
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
207
|
+
/**
|
|
208
|
+
* Create a new session for a document type.
|
|
209
|
+
* This automatically creates a document with default values.
|
|
210
|
+
*/
|
|
211
|
+
createSession(documentTypeId: string): Promise<CreateSessionResponse>;
|
|
212
|
+
/**
|
|
213
|
+
* Get an existing session.
|
|
214
|
+
*/
|
|
213
215
|
getSession(id: string): Promise<Session>;
|
|
214
|
-
deleteSession(id: string): Promise<void>;
|
|
215
216
|
/**
|
|
216
|
-
* Send a message to the session with SSE streaming
|
|
217
|
+
* Send a message to the session with SSE streaming.
|
|
217
218
|
*/
|
|
218
219
|
sendMessage(sessionId: string, message: string, onEvent: (event: SSEEvent) => void): Promise<void>;
|
|
219
220
|
/**
|
|
220
|
-
* Send a quick action to the session
|
|
221
|
+
* Send a quick action to the session.
|
|
222
|
+
* For actions that trigger AI (task_action:*), returns SSE stream.
|
|
223
|
+
* For other actions (select_task:*, resume_task:*), returns session directly.
|
|
221
224
|
*/
|
|
222
|
-
sendQuickAction(sessionId: string, action: string,
|
|
225
|
+
sendQuickAction(sessionId: string, action: string, onEvent?: (event: SSEEvent) => void): Promise<Session>;
|
|
223
226
|
/**
|
|
224
|
-
* Apply the pending value for the active task
|
|
227
|
+
* Apply the pending value for the active task.
|
|
225
228
|
*/
|
|
226
|
-
applyPendingValue(sessionId: string): Promise<
|
|
229
|
+
applyPendingValue(sessionId: string): Promise<ApplyResponse>;
|
|
227
230
|
/**
|
|
228
|
-
* Skip the active task
|
|
231
|
+
* Skip the active task.
|
|
229
232
|
*/
|
|
230
233
|
skipTask(sessionId: string): Promise<Session>;
|
|
231
234
|
private processSSEStream;
|
|
232
235
|
}
|
|
233
236
|
|
|
234
|
-
export { type ChatMessage, type Document, type DocumentType, type DocumentTypeSchema, type FieldDefinition, InformedAIClient, InformedAIProvider, InformedAssistant, type InformedAssistantConfig, type QuickAction, type SSEEvent, type Session, type TaskConfig, type TaskState, type
|
|
237
|
+
export { type ChatMessage, type Document, type DocumentType, type DocumentTypeSchema, type FieldDefinition, InformedAIClient, InformedAIProvider, InformedAssistant, type InformedAssistantConfig, type QuickAction, type SSEEvent, type Session, type TaskConfig, type TaskState, type UseSessionReturn, type WidgetMessage, type WidgetTheme, useInformedAI, useSession };
|
package/dist/index.js
CHANGED
|
@@ -23,7 +23,6 @@ __export(index_exports, {
|
|
|
23
23
|
InformedAIClient: () => InformedAIClient,
|
|
24
24
|
InformedAIProvider: () => InformedAIProvider,
|
|
25
25
|
InformedAssistant: () => InformedAssistant,
|
|
26
|
-
useDocument: () => useDocument,
|
|
27
26
|
useInformedAI: () => useInformedAI,
|
|
28
27
|
useSession: () => useSession
|
|
29
28
|
});
|
|
@@ -38,14 +37,12 @@ var import_react = require("react");
|
|
|
38
37
|
// src/utils/api-client.ts
|
|
39
38
|
var DEFAULT_API_URL = "https://api.informedassistant.ai/api/v1";
|
|
40
39
|
var InformedAIClient = class {
|
|
41
|
-
constructor(
|
|
42
|
-
this.apiKey = apiKey;
|
|
40
|
+
constructor(apiUrl) {
|
|
43
41
|
this.apiUrl = apiUrl || DEFAULT_API_URL;
|
|
44
42
|
}
|
|
45
43
|
getHeaders() {
|
|
46
44
|
return {
|
|
47
|
-
"Content-Type": "application/json"
|
|
48
|
-
"Authorization": `Bearer ${this.apiKey}`
|
|
45
|
+
"Content-Type": "application/json"
|
|
49
46
|
};
|
|
50
47
|
}
|
|
51
48
|
async request(endpoint, options = {}) {
|
|
@@ -66,40 +63,29 @@ var InformedAIClient = class {
|
|
|
66
63
|
return response.json();
|
|
67
64
|
}
|
|
68
65
|
// ========================================================================
|
|
69
|
-
//
|
|
66
|
+
// Widget Session Operations (keyless)
|
|
70
67
|
// ========================================================================
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
async updateDocumentField(documentId, field, value) {
|
|
78
|
-
return this.request(`/documents/${documentId}/field`, {
|
|
79
|
-
method: "PATCH",
|
|
80
|
-
body: JSON.stringify({ field, value })
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
// ========================================================================
|
|
84
|
-
// Session Operations
|
|
85
|
-
// ========================================================================
|
|
86
|
-
async createSession(documentId) {
|
|
87
|
-
return this.request("/sessions", {
|
|
68
|
+
/**
|
|
69
|
+
* Create a new session for a document type.
|
|
70
|
+
* This automatically creates a document with default values.
|
|
71
|
+
*/
|
|
72
|
+
async createSession(documentTypeId) {
|
|
73
|
+
return this.request("/widget/sessions", {
|
|
88
74
|
method: "POST",
|
|
89
|
-
body: JSON.stringify({
|
|
75
|
+
body: JSON.stringify({ documentTypeId })
|
|
90
76
|
});
|
|
91
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Get an existing session.
|
|
80
|
+
*/
|
|
92
81
|
async getSession(id) {
|
|
93
|
-
return this.request(`/sessions/${id}`);
|
|
94
|
-
}
|
|
95
|
-
async deleteSession(id) {
|
|
96
|
-
await this.request(`/sessions/${id}`, { method: "DELETE" });
|
|
82
|
+
return this.request(`/widget/sessions/${id}`);
|
|
97
83
|
}
|
|
98
84
|
/**
|
|
99
|
-
* Send a message to the session with SSE streaming
|
|
85
|
+
* Send a message to the session with SSE streaming.
|
|
100
86
|
*/
|
|
101
87
|
async sendMessage(sessionId, message, onEvent) {
|
|
102
|
-
const response = await fetch(`${this.apiUrl}/sessions/${sessionId}/message`, {
|
|
88
|
+
const response = await fetch(`${this.apiUrl}/widget/sessions/${sessionId}/message`, {
|
|
103
89
|
method: "POST",
|
|
104
90
|
headers: this.getHeaders(),
|
|
105
91
|
body: JSON.stringify({ message })
|
|
@@ -111,43 +97,50 @@ var InformedAIClient = class {
|
|
|
111
97
|
await this.processSSEStream(response, onEvent);
|
|
112
98
|
}
|
|
113
99
|
/**
|
|
114
|
-
* Send a quick action to the session
|
|
100
|
+
* Send a quick action to the session.
|
|
101
|
+
* For actions that trigger AI (task_action:*), returns SSE stream.
|
|
102
|
+
* For other actions (select_task:*, resume_task:*), returns session directly.
|
|
115
103
|
*/
|
|
116
|
-
async sendQuickAction(sessionId, action,
|
|
117
|
-
const response = await fetch(`${this.apiUrl}/sessions/${sessionId}/quick-action`, {
|
|
104
|
+
async sendQuickAction(sessionId, action, onEvent) {
|
|
105
|
+
const response = await fetch(`${this.apiUrl}/widget/sessions/${sessionId}/quick-action`, {
|
|
118
106
|
method: "POST",
|
|
119
107
|
headers: this.getHeaders(),
|
|
120
|
-
body: JSON.stringify({ action
|
|
108
|
+
body: JSON.stringify({ action })
|
|
121
109
|
});
|
|
122
110
|
if (!response.ok) {
|
|
123
111
|
const error = await response.json().catch(() => ({ error: "Request failed" }));
|
|
124
112
|
throw new Error(error.error || `HTTP ${response.status}`);
|
|
125
113
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
114
|
+
const contentType = response.headers.get("content-type") || "";
|
|
115
|
+
if (contentType.includes("text/event-stream")) {
|
|
116
|
+
let finalSession = null;
|
|
117
|
+
await this.processSSEStream(response, (event) => {
|
|
118
|
+
onEvent?.(event);
|
|
119
|
+
if (event.session) {
|
|
120
|
+
finalSession = event.session;
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
if (!finalSession) {
|
|
124
|
+
return this.getSession(sessionId);
|
|
131
125
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
126
|
+
return finalSession;
|
|
127
|
+
} else {
|
|
128
|
+
return response.json();
|
|
135
129
|
}
|
|
136
|
-
return finalSession;
|
|
137
130
|
}
|
|
138
131
|
/**
|
|
139
|
-
* Apply the pending value for the active task
|
|
132
|
+
* Apply the pending value for the active task.
|
|
140
133
|
*/
|
|
141
134
|
async applyPendingValue(sessionId) {
|
|
142
|
-
return this.request(`/sessions/${sessionId}/apply`, {
|
|
135
|
+
return this.request(`/widget/sessions/${sessionId}/apply`, {
|
|
143
136
|
method: "POST"
|
|
144
137
|
});
|
|
145
138
|
}
|
|
146
139
|
/**
|
|
147
|
-
* Skip the active task
|
|
140
|
+
* Skip the active task.
|
|
148
141
|
*/
|
|
149
142
|
async skipTask(sessionId) {
|
|
150
|
-
return this.request(`/sessions/${sessionId}/skip`, {
|
|
143
|
+
return this.request(`/widget/sessions/${sessionId}/skip`, {
|
|
151
144
|
method: "POST"
|
|
152
145
|
});
|
|
153
146
|
}
|
|
@@ -211,25 +204,37 @@ function InformedAIProvider({ config, children }) {
|
|
|
211
204
|
const [streamingContent, setStreamingContent] = (0, import_react.useState)("");
|
|
212
205
|
const clientRef = (0, import_react.useRef)(null);
|
|
213
206
|
(0, import_react.useEffect)(() => {
|
|
214
|
-
clientRef.current = new InformedAIClient(config.
|
|
215
|
-
}, [config.
|
|
207
|
+
clientRef.current = new InformedAIClient(config.apiUrl);
|
|
208
|
+
}, [config.apiUrl]);
|
|
216
209
|
(0, import_react.useEffect)(() => {
|
|
217
210
|
async function initialize() {
|
|
218
211
|
if (!clientRef.current) return;
|
|
219
212
|
try {
|
|
220
213
|
setIsLoading(true);
|
|
221
214
|
setError(null);
|
|
222
|
-
const doc = await clientRef.current.getDocument(config.documentId);
|
|
223
|
-
setDocument(doc);
|
|
224
|
-
const dt = await clientRef.current.getDocumentType(doc.documentTypeId);
|
|
225
|
-
setDocumentType(dt);
|
|
226
215
|
let sess;
|
|
216
|
+
let doc = null;
|
|
217
|
+
let dt = null;
|
|
227
218
|
if (config.sessionId) {
|
|
228
219
|
sess = await clientRef.current.getSession(config.sessionId);
|
|
229
220
|
} else {
|
|
230
|
-
|
|
221
|
+
const result = await clientRef.current.createSession(config.documentTypeId);
|
|
222
|
+
sess = result.session;
|
|
223
|
+
doc = result.document;
|
|
224
|
+
dt = {
|
|
225
|
+
id: result.documentType.id,
|
|
226
|
+
name: result.documentType.name,
|
|
227
|
+
displayName: result.documentType.displayName,
|
|
228
|
+
schema: result.documentType.schema,
|
|
229
|
+
workspaceId: "",
|
|
230
|
+
taskConfigs: {},
|
|
231
|
+
createdAt: "",
|
|
232
|
+
updatedAt: ""
|
|
233
|
+
};
|
|
231
234
|
}
|
|
232
235
|
setSession(sess);
|
|
236
|
+
if (doc) setDocument(doc);
|
|
237
|
+
if (dt) setDocumentType(dt);
|
|
233
238
|
config.onSessionChange?.(sess);
|
|
234
239
|
} catch (err) {
|
|
235
240
|
const error2 = err instanceof Error ? err : new Error("Initialization failed");
|
|
@@ -240,7 +245,7 @@ function InformedAIProvider({ config, children }) {
|
|
|
240
245
|
}
|
|
241
246
|
}
|
|
242
247
|
initialize();
|
|
243
|
-
}, [config.
|
|
248
|
+
}, [config.documentTypeId, config.sessionId]);
|
|
244
249
|
const handleSSEEvent = (0, import_react.useCallback)((event) => {
|
|
245
250
|
if (event.type === "content" && event.content) {
|
|
246
251
|
setStreamingContent((prev) => prev + event.content);
|
|
@@ -249,11 +254,6 @@ function InformedAIProvider({ config, children }) {
|
|
|
249
254
|
if (event.session) {
|
|
250
255
|
setSession(event.session);
|
|
251
256
|
config.onSessionChange?.(event.session);
|
|
252
|
-
if (event.session.activeTask) {
|
|
253
|
-
const taskState = event.session.taskStates[event.session.activeTask];
|
|
254
|
-
if (taskState?.pendingValue !== void 0) {
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
257
|
}
|
|
258
258
|
setStreamingContent("");
|
|
259
259
|
setIsStreaming(false);
|
|
@@ -279,7 +279,7 @@ function InformedAIProvider({ config, children }) {
|
|
|
279
279
|
setIsStreaming(false);
|
|
280
280
|
}
|
|
281
281
|
}, [session, handleSSEEvent, config]);
|
|
282
|
-
const sendQuickAction = (0, import_react.useCallback)(async (action
|
|
282
|
+
const sendQuickAction = (0, import_react.useCallback)(async (action) => {
|
|
283
283
|
if (!clientRef.current || !session) return;
|
|
284
284
|
try {
|
|
285
285
|
setIsStreaming(true);
|
|
@@ -288,7 +288,6 @@ function InformedAIProvider({ config, children }) {
|
|
|
288
288
|
const newSession = await clientRef.current.sendQuickAction(
|
|
289
289
|
session.id,
|
|
290
290
|
action,
|
|
291
|
-
payload,
|
|
292
291
|
handleSSEEvent
|
|
293
292
|
);
|
|
294
293
|
setSession(newSession);
|
|
@@ -305,14 +304,10 @@ function InformedAIProvider({ config, children }) {
|
|
|
305
304
|
if (!clientRef.current || !session) return;
|
|
306
305
|
try {
|
|
307
306
|
setError(null);
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
config.onSessionChange?.(newSession);
|
|
313
|
-
if (activeTask && pendingValue !== void 0) {
|
|
314
|
-
config.onFieldApply?.(activeTask, pendingValue);
|
|
315
|
-
}
|
|
307
|
+
const result = await clientRef.current.applyPendingValue(session.id);
|
|
308
|
+
setSession(result.session);
|
|
309
|
+
config.onSessionChange?.(result.session);
|
|
310
|
+
config.onFieldApply?.(result.appliedField, result.appliedValue);
|
|
316
311
|
} catch (err) {
|
|
317
312
|
const error2 = err instanceof Error ? err : new Error("Failed to apply value");
|
|
318
313
|
setError(error2);
|
|
@@ -711,7 +706,8 @@ function AssistantWidget({ className, theme, position = "inline", defaultCollaps
|
|
|
711
706
|
}
|
|
712
707
|
function MessageBubble({ message, theme, onQuickAction }) {
|
|
713
708
|
const isUser = message.role === "user";
|
|
714
|
-
|
|
709
|
+
const hasQuickActions = message.quickActions && message.quickActions.length > 0;
|
|
710
|
+
if ((message.type === "quick_actions" || !message.content) && hasQuickActions) {
|
|
715
711
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: "8px" }, children: message.quickActions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
716
712
|
"button",
|
|
717
713
|
{
|
|
@@ -739,31 +735,61 @@ function MessageBubble({ message, theme, onQuickAction }) {
|
|
|
739
735
|
action.id
|
|
740
736
|
)) });
|
|
741
737
|
}
|
|
742
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.
|
|
738
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
743
739
|
"div",
|
|
744
740
|
{
|
|
745
741
|
style: {
|
|
746
742
|
display: "flex",
|
|
747
|
-
|
|
743
|
+
flexDirection: "column",
|
|
744
|
+
alignItems: isUser ? "flex-end" : "flex-start",
|
|
745
|
+
gap: "8px"
|
|
748
746
|
},
|
|
749
|
-
children:
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
747
|
+
children: [
|
|
748
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
749
|
+
"div",
|
|
750
|
+
{
|
|
751
|
+
style: {
|
|
752
|
+
maxWidth: "85%",
|
|
753
|
+
padding: "12px 16px",
|
|
754
|
+
backgroundColor: isUser ? theme.primaryColor : "#f5f5f5",
|
|
755
|
+
color: isUser ? "#fff" : theme.textColor,
|
|
756
|
+
borderRadius: "12px",
|
|
757
|
+
borderBottomRightRadius: isUser ? "4px" : "12px",
|
|
758
|
+
borderBottomLeftRadius: isUser ? "12px" : "4px",
|
|
759
|
+
fontSize: "14px",
|
|
760
|
+
lineHeight: 1.5,
|
|
761
|
+
whiteSpace: "pre-wrap"
|
|
762
|
+
},
|
|
763
|
+
children: message.content
|
|
764
|
+
}
|
|
765
|
+
),
|
|
766
|
+
hasQuickActions && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: "8px", maxWidth: "85%" }, children: message.quickActions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
767
|
+
"button",
|
|
768
|
+
{
|
|
769
|
+
onClick: () => onQuickAction(action),
|
|
770
|
+
style: {
|
|
771
|
+
padding: "8px 14px",
|
|
772
|
+
backgroundColor: "#f5f5f5",
|
|
773
|
+
border: "1px solid #e5e5e5",
|
|
774
|
+
borderRadius: "20px",
|
|
775
|
+
fontSize: "13px",
|
|
776
|
+
cursor: "pointer",
|
|
777
|
+
color: theme.textColor,
|
|
778
|
+
transition: "all 0.15s"
|
|
779
|
+
},
|
|
780
|
+
onMouseOver: (e) => {
|
|
781
|
+
e.currentTarget.style.backgroundColor = `${theme.primaryColor}15`;
|
|
782
|
+
e.currentTarget.style.borderColor = theme.primaryColor;
|
|
783
|
+
},
|
|
784
|
+
onMouseOut: (e) => {
|
|
785
|
+
e.currentTarget.style.backgroundColor = "#f5f5f5";
|
|
786
|
+
e.currentTarget.style.borderColor = "#e5e5e5";
|
|
787
|
+
},
|
|
788
|
+
children: action.label
|
|
763
789
|
},
|
|
764
|
-
|
|
765
|
-
}
|
|
766
|
-
|
|
790
|
+
action.id
|
|
791
|
+
)) })
|
|
792
|
+
]
|
|
767
793
|
}
|
|
768
794
|
);
|
|
769
795
|
}
|
|
@@ -809,15 +835,15 @@ function LoadingSpinner({ size = 20 }) {
|
|
|
809
835
|
// src/hooks/useSession.ts
|
|
810
836
|
var import_react3 = require("react");
|
|
811
837
|
function useSession(options) {
|
|
812
|
-
const {
|
|
838
|
+
const { apiUrl, documentTypeId, sessionId, onSessionChange, onError } = options;
|
|
813
839
|
const [session, setSession] = (0, import_react3.useState)(null);
|
|
814
840
|
const [isLoading, setIsLoading] = (0, import_react3.useState)(true);
|
|
815
841
|
const [error, setError] = (0, import_react3.useState)(null);
|
|
816
842
|
const clientRef = (0, import_react3.useRef)(null);
|
|
817
843
|
const isStreamingRef = (0, import_react3.useRef)(false);
|
|
818
844
|
(0, import_react3.useEffect)(() => {
|
|
819
|
-
clientRef.current = new InformedAIClient(
|
|
820
|
-
}, [
|
|
845
|
+
clientRef.current = new InformedAIClient(apiUrl);
|
|
846
|
+
}, [apiUrl]);
|
|
821
847
|
(0, import_react3.useEffect)(() => {
|
|
822
848
|
async function initialize() {
|
|
823
849
|
if (!clientRef.current) return;
|
|
@@ -828,7 +854,8 @@ function useSession(options) {
|
|
|
828
854
|
if (sessionId) {
|
|
829
855
|
sess = await clientRef.current.getSession(sessionId);
|
|
830
856
|
} else {
|
|
831
|
-
|
|
857
|
+
const result = await clientRef.current.createSession(documentTypeId);
|
|
858
|
+
sess = result.session;
|
|
832
859
|
}
|
|
833
860
|
setSession(sess);
|
|
834
861
|
onSessionChange?.(sess);
|
|
@@ -841,7 +868,7 @@ function useSession(options) {
|
|
|
841
868
|
}
|
|
842
869
|
}
|
|
843
870
|
initialize();
|
|
844
|
-
}, [
|
|
871
|
+
}, [documentTypeId, sessionId, onSessionChange, onError]);
|
|
845
872
|
const handleSSEEvent = (0, import_react3.useCallback)((event) => {
|
|
846
873
|
if (event.type === "done" || event.type === "session_update") {
|
|
847
874
|
if (event.session) {
|
|
@@ -870,7 +897,7 @@ function useSession(options) {
|
|
|
870
897
|
isStreamingRef.current = false;
|
|
871
898
|
}
|
|
872
899
|
}, [session, handleSSEEvent, onError]);
|
|
873
|
-
const sendQuickAction = (0, import_react3.useCallback)(async (action
|
|
900
|
+
const sendQuickAction = (0, import_react3.useCallback)(async (action) => {
|
|
874
901
|
if (!clientRef.current || !session || isStreamingRef.current) return;
|
|
875
902
|
try {
|
|
876
903
|
isStreamingRef.current = true;
|
|
@@ -878,7 +905,6 @@ function useSession(options) {
|
|
|
878
905
|
const newSession = await clientRef.current.sendQuickAction(
|
|
879
906
|
session.id,
|
|
880
907
|
action,
|
|
881
|
-
payload,
|
|
882
908
|
handleSSEEvent
|
|
883
909
|
);
|
|
884
910
|
setSession(newSession);
|
|
@@ -895,9 +921,9 @@ function useSession(options) {
|
|
|
895
921
|
if (!clientRef.current || !session) return;
|
|
896
922
|
try {
|
|
897
923
|
setError(null);
|
|
898
|
-
const
|
|
899
|
-
setSession(
|
|
900
|
-
onSessionChange?.(
|
|
924
|
+
const result = await clientRef.current.applyPendingValue(session.id);
|
|
925
|
+
setSession(result.session);
|
|
926
|
+
onSessionChange?.(result.session);
|
|
901
927
|
} catch (err) {
|
|
902
928
|
const error2 = err instanceof Error ? err : new Error("Failed to apply value");
|
|
903
929
|
setError(error2);
|
|
@@ -927,69 +953,11 @@ function useSession(options) {
|
|
|
927
953
|
skipTask
|
|
928
954
|
};
|
|
929
955
|
}
|
|
930
|
-
|
|
931
|
-
// src/hooks/useDocument.ts
|
|
932
|
-
var import_react4 = require("react");
|
|
933
|
-
function useDocument(options) {
|
|
934
|
-
const { apiKey, apiUrl, documentId, onError } = options;
|
|
935
|
-
const [document, setDocument] = (0, import_react4.useState)(null);
|
|
936
|
-
const [documentType, setDocumentType] = (0, import_react4.useState)(null);
|
|
937
|
-
const [isLoading, setIsLoading] = (0, import_react4.useState)(true);
|
|
938
|
-
const [error, setError] = (0, import_react4.useState)(null);
|
|
939
|
-
const clientRef = (0, import_react4.useRef)(null);
|
|
940
|
-
(0, import_react4.useEffect)(() => {
|
|
941
|
-
clientRef.current = new InformedAIClient(apiKey, apiUrl);
|
|
942
|
-
}, [apiKey, apiUrl]);
|
|
943
|
-
const fetchDocument = (0, import_react4.useCallback)(async () => {
|
|
944
|
-
if (!clientRef.current) return;
|
|
945
|
-
try {
|
|
946
|
-
setIsLoading(true);
|
|
947
|
-
setError(null);
|
|
948
|
-
const doc = await clientRef.current.getDocument(documentId);
|
|
949
|
-
setDocument(doc);
|
|
950
|
-
const dt = await clientRef.current.getDocumentType(doc.documentTypeId);
|
|
951
|
-
setDocumentType(dt);
|
|
952
|
-
} catch (err) {
|
|
953
|
-
const error2 = err instanceof Error ? err : new Error("Failed to fetch document");
|
|
954
|
-
setError(error2);
|
|
955
|
-
onError?.(error2);
|
|
956
|
-
} finally {
|
|
957
|
-
setIsLoading(false);
|
|
958
|
-
}
|
|
959
|
-
}, [documentId, onError]);
|
|
960
|
-
(0, import_react4.useEffect)(() => {
|
|
961
|
-
fetchDocument();
|
|
962
|
-
}, [fetchDocument]);
|
|
963
|
-
const updateField = (0, import_react4.useCallback)(async (fieldName, value) => {
|
|
964
|
-
if (!clientRef.current || !document) return;
|
|
965
|
-
try {
|
|
966
|
-
setError(null);
|
|
967
|
-
const updatedDoc = await clientRef.current.updateDocumentField(document.id, fieldName, value);
|
|
968
|
-
setDocument(updatedDoc);
|
|
969
|
-
} catch (err) {
|
|
970
|
-
const error2 = err instanceof Error ? err : new Error("Failed to update field");
|
|
971
|
-
setError(error2);
|
|
972
|
-
onError?.(error2);
|
|
973
|
-
}
|
|
974
|
-
}, [document, onError]);
|
|
975
|
-
const refetch = (0, import_react4.useCallback)(async () => {
|
|
976
|
-
await fetchDocument();
|
|
977
|
-
}, [fetchDocument]);
|
|
978
|
-
return {
|
|
979
|
-
document,
|
|
980
|
-
documentType,
|
|
981
|
-
isLoading,
|
|
982
|
-
error,
|
|
983
|
-
updateField,
|
|
984
|
-
refetch
|
|
985
|
-
};
|
|
986
|
-
}
|
|
987
956
|
// Annotate the CommonJS export names for ESM import in node:
|
|
988
957
|
0 && (module.exports = {
|
|
989
958
|
InformedAIClient,
|
|
990
959
|
InformedAIProvider,
|
|
991
960
|
InformedAssistant,
|
|
992
|
-
useDocument,
|
|
993
961
|
useInformedAI,
|
|
994
962
|
useSession
|
|
995
963
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -7,14 +7,12 @@ import { createContext, useContext, useEffect, useState, useCallback, useRef } f
|
|
|
7
7
|
// src/utils/api-client.ts
|
|
8
8
|
var DEFAULT_API_URL = "https://api.informedassistant.ai/api/v1";
|
|
9
9
|
var InformedAIClient = class {
|
|
10
|
-
constructor(
|
|
11
|
-
this.apiKey = apiKey;
|
|
10
|
+
constructor(apiUrl) {
|
|
12
11
|
this.apiUrl = apiUrl || DEFAULT_API_URL;
|
|
13
12
|
}
|
|
14
13
|
getHeaders() {
|
|
15
14
|
return {
|
|
16
|
-
"Content-Type": "application/json"
|
|
17
|
-
"Authorization": `Bearer ${this.apiKey}`
|
|
15
|
+
"Content-Type": "application/json"
|
|
18
16
|
};
|
|
19
17
|
}
|
|
20
18
|
async request(endpoint, options = {}) {
|
|
@@ -35,40 +33,29 @@ var InformedAIClient = class {
|
|
|
35
33
|
return response.json();
|
|
36
34
|
}
|
|
37
35
|
// ========================================================================
|
|
38
|
-
//
|
|
36
|
+
// Widget Session Operations (keyless)
|
|
39
37
|
// ========================================================================
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
async updateDocumentField(documentId, field, value) {
|
|
47
|
-
return this.request(`/documents/${documentId}/field`, {
|
|
48
|
-
method: "PATCH",
|
|
49
|
-
body: JSON.stringify({ field, value })
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
// ========================================================================
|
|
53
|
-
// Session Operations
|
|
54
|
-
// ========================================================================
|
|
55
|
-
async createSession(documentId) {
|
|
56
|
-
return this.request("/sessions", {
|
|
38
|
+
/**
|
|
39
|
+
* Create a new session for a document type.
|
|
40
|
+
* This automatically creates a document with default values.
|
|
41
|
+
*/
|
|
42
|
+
async createSession(documentTypeId) {
|
|
43
|
+
return this.request("/widget/sessions", {
|
|
57
44
|
method: "POST",
|
|
58
|
-
body: JSON.stringify({
|
|
45
|
+
body: JSON.stringify({ documentTypeId })
|
|
59
46
|
});
|
|
60
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Get an existing session.
|
|
50
|
+
*/
|
|
61
51
|
async getSession(id) {
|
|
62
|
-
return this.request(`/sessions/${id}`);
|
|
63
|
-
}
|
|
64
|
-
async deleteSession(id) {
|
|
65
|
-
await this.request(`/sessions/${id}`, { method: "DELETE" });
|
|
52
|
+
return this.request(`/widget/sessions/${id}`);
|
|
66
53
|
}
|
|
67
54
|
/**
|
|
68
|
-
* Send a message to the session with SSE streaming
|
|
55
|
+
* Send a message to the session with SSE streaming.
|
|
69
56
|
*/
|
|
70
57
|
async sendMessage(sessionId, message, onEvent) {
|
|
71
|
-
const response = await fetch(`${this.apiUrl}/sessions/${sessionId}/message`, {
|
|
58
|
+
const response = await fetch(`${this.apiUrl}/widget/sessions/${sessionId}/message`, {
|
|
72
59
|
method: "POST",
|
|
73
60
|
headers: this.getHeaders(),
|
|
74
61
|
body: JSON.stringify({ message })
|
|
@@ -80,43 +67,50 @@ var InformedAIClient = class {
|
|
|
80
67
|
await this.processSSEStream(response, onEvent);
|
|
81
68
|
}
|
|
82
69
|
/**
|
|
83
|
-
* Send a quick action to the session
|
|
70
|
+
* Send a quick action to the session.
|
|
71
|
+
* For actions that trigger AI (task_action:*), returns SSE stream.
|
|
72
|
+
* For other actions (select_task:*, resume_task:*), returns session directly.
|
|
84
73
|
*/
|
|
85
|
-
async sendQuickAction(sessionId, action,
|
|
86
|
-
const response = await fetch(`${this.apiUrl}/sessions/${sessionId}/quick-action`, {
|
|
74
|
+
async sendQuickAction(sessionId, action, onEvent) {
|
|
75
|
+
const response = await fetch(`${this.apiUrl}/widget/sessions/${sessionId}/quick-action`, {
|
|
87
76
|
method: "POST",
|
|
88
77
|
headers: this.getHeaders(),
|
|
89
|
-
body: JSON.stringify({ action
|
|
78
|
+
body: JSON.stringify({ action })
|
|
90
79
|
});
|
|
91
80
|
if (!response.ok) {
|
|
92
81
|
const error = await response.json().catch(() => ({ error: "Request failed" }));
|
|
93
82
|
throw new Error(error.error || `HTTP ${response.status}`);
|
|
94
83
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
84
|
+
const contentType = response.headers.get("content-type") || "";
|
|
85
|
+
if (contentType.includes("text/event-stream")) {
|
|
86
|
+
let finalSession = null;
|
|
87
|
+
await this.processSSEStream(response, (event) => {
|
|
88
|
+
onEvent?.(event);
|
|
89
|
+
if (event.session) {
|
|
90
|
+
finalSession = event.session;
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
if (!finalSession) {
|
|
94
|
+
return this.getSession(sessionId);
|
|
100
95
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
96
|
+
return finalSession;
|
|
97
|
+
} else {
|
|
98
|
+
return response.json();
|
|
104
99
|
}
|
|
105
|
-
return finalSession;
|
|
106
100
|
}
|
|
107
101
|
/**
|
|
108
|
-
* Apply the pending value for the active task
|
|
102
|
+
* Apply the pending value for the active task.
|
|
109
103
|
*/
|
|
110
104
|
async applyPendingValue(sessionId) {
|
|
111
|
-
return this.request(`/sessions/${sessionId}/apply`, {
|
|
105
|
+
return this.request(`/widget/sessions/${sessionId}/apply`, {
|
|
112
106
|
method: "POST"
|
|
113
107
|
});
|
|
114
108
|
}
|
|
115
109
|
/**
|
|
116
|
-
* Skip the active task
|
|
110
|
+
* Skip the active task.
|
|
117
111
|
*/
|
|
118
112
|
async skipTask(sessionId) {
|
|
119
|
-
return this.request(`/sessions/${sessionId}/skip`, {
|
|
113
|
+
return this.request(`/widget/sessions/${sessionId}/skip`, {
|
|
120
114
|
method: "POST"
|
|
121
115
|
});
|
|
122
116
|
}
|
|
@@ -180,25 +174,37 @@ function InformedAIProvider({ config, children }) {
|
|
|
180
174
|
const [streamingContent, setStreamingContent] = useState("");
|
|
181
175
|
const clientRef = useRef(null);
|
|
182
176
|
useEffect(() => {
|
|
183
|
-
clientRef.current = new InformedAIClient(config.
|
|
184
|
-
}, [config.
|
|
177
|
+
clientRef.current = new InformedAIClient(config.apiUrl);
|
|
178
|
+
}, [config.apiUrl]);
|
|
185
179
|
useEffect(() => {
|
|
186
180
|
async function initialize() {
|
|
187
181
|
if (!clientRef.current) return;
|
|
188
182
|
try {
|
|
189
183
|
setIsLoading(true);
|
|
190
184
|
setError(null);
|
|
191
|
-
const doc = await clientRef.current.getDocument(config.documentId);
|
|
192
|
-
setDocument(doc);
|
|
193
|
-
const dt = await clientRef.current.getDocumentType(doc.documentTypeId);
|
|
194
|
-
setDocumentType(dt);
|
|
195
185
|
let sess;
|
|
186
|
+
let doc = null;
|
|
187
|
+
let dt = null;
|
|
196
188
|
if (config.sessionId) {
|
|
197
189
|
sess = await clientRef.current.getSession(config.sessionId);
|
|
198
190
|
} else {
|
|
199
|
-
|
|
191
|
+
const result = await clientRef.current.createSession(config.documentTypeId);
|
|
192
|
+
sess = result.session;
|
|
193
|
+
doc = result.document;
|
|
194
|
+
dt = {
|
|
195
|
+
id: result.documentType.id,
|
|
196
|
+
name: result.documentType.name,
|
|
197
|
+
displayName: result.documentType.displayName,
|
|
198
|
+
schema: result.documentType.schema,
|
|
199
|
+
workspaceId: "",
|
|
200
|
+
taskConfigs: {},
|
|
201
|
+
createdAt: "",
|
|
202
|
+
updatedAt: ""
|
|
203
|
+
};
|
|
200
204
|
}
|
|
201
205
|
setSession(sess);
|
|
206
|
+
if (doc) setDocument(doc);
|
|
207
|
+
if (dt) setDocumentType(dt);
|
|
202
208
|
config.onSessionChange?.(sess);
|
|
203
209
|
} catch (err) {
|
|
204
210
|
const error2 = err instanceof Error ? err : new Error("Initialization failed");
|
|
@@ -209,7 +215,7 @@ function InformedAIProvider({ config, children }) {
|
|
|
209
215
|
}
|
|
210
216
|
}
|
|
211
217
|
initialize();
|
|
212
|
-
}, [config.
|
|
218
|
+
}, [config.documentTypeId, config.sessionId]);
|
|
213
219
|
const handleSSEEvent = useCallback((event) => {
|
|
214
220
|
if (event.type === "content" && event.content) {
|
|
215
221
|
setStreamingContent((prev) => prev + event.content);
|
|
@@ -218,11 +224,6 @@ function InformedAIProvider({ config, children }) {
|
|
|
218
224
|
if (event.session) {
|
|
219
225
|
setSession(event.session);
|
|
220
226
|
config.onSessionChange?.(event.session);
|
|
221
|
-
if (event.session.activeTask) {
|
|
222
|
-
const taskState = event.session.taskStates[event.session.activeTask];
|
|
223
|
-
if (taskState?.pendingValue !== void 0) {
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
227
|
}
|
|
227
228
|
setStreamingContent("");
|
|
228
229
|
setIsStreaming(false);
|
|
@@ -248,7 +249,7 @@ function InformedAIProvider({ config, children }) {
|
|
|
248
249
|
setIsStreaming(false);
|
|
249
250
|
}
|
|
250
251
|
}, [session, handleSSEEvent, config]);
|
|
251
|
-
const sendQuickAction = useCallback(async (action
|
|
252
|
+
const sendQuickAction = useCallback(async (action) => {
|
|
252
253
|
if (!clientRef.current || !session) return;
|
|
253
254
|
try {
|
|
254
255
|
setIsStreaming(true);
|
|
@@ -257,7 +258,6 @@ function InformedAIProvider({ config, children }) {
|
|
|
257
258
|
const newSession = await clientRef.current.sendQuickAction(
|
|
258
259
|
session.id,
|
|
259
260
|
action,
|
|
260
|
-
payload,
|
|
261
261
|
handleSSEEvent
|
|
262
262
|
);
|
|
263
263
|
setSession(newSession);
|
|
@@ -274,14 +274,10 @@ function InformedAIProvider({ config, children }) {
|
|
|
274
274
|
if (!clientRef.current || !session) return;
|
|
275
275
|
try {
|
|
276
276
|
setError(null);
|
|
277
|
-
const
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
config.onSessionChange?.(newSession);
|
|
282
|
-
if (activeTask && pendingValue !== void 0) {
|
|
283
|
-
config.onFieldApply?.(activeTask, pendingValue);
|
|
284
|
-
}
|
|
277
|
+
const result = await clientRef.current.applyPendingValue(session.id);
|
|
278
|
+
setSession(result.session);
|
|
279
|
+
config.onSessionChange?.(result.session);
|
|
280
|
+
config.onFieldApply?.(result.appliedField, result.appliedValue);
|
|
285
281
|
} catch (err) {
|
|
286
282
|
const error2 = err instanceof Error ? err : new Error("Failed to apply value");
|
|
287
283
|
setError(error2);
|
|
@@ -680,7 +676,8 @@ function AssistantWidget({ className, theme, position = "inline", defaultCollaps
|
|
|
680
676
|
}
|
|
681
677
|
function MessageBubble({ message, theme, onQuickAction }) {
|
|
682
678
|
const isUser = message.role === "user";
|
|
683
|
-
|
|
679
|
+
const hasQuickActions = message.quickActions && message.quickActions.length > 0;
|
|
680
|
+
if ((message.type === "quick_actions" || !message.content) && hasQuickActions) {
|
|
684
681
|
return /* @__PURE__ */ jsx2("div", { style: { display: "flex", flexWrap: "wrap", gap: "8px" }, children: message.quickActions.map((action) => /* @__PURE__ */ jsx2(
|
|
685
682
|
"button",
|
|
686
683
|
{
|
|
@@ -708,31 +705,61 @@ function MessageBubble({ message, theme, onQuickAction }) {
|
|
|
708
705
|
action.id
|
|
709
706
|
)) });
|
|
710
707
|
}
|
|
711
|
-
return /* @__PURE__ */
|
|
708
|
+
return /* @__PURE__ */ jsxs(
|
|
712
709
|
"div",
|
|
713
710
|
{
|
|
714
711
|
style: {
|
|
715
712
|
display: "flex",
|
|
716
|
-
|
|
713
|
+
flexDirection: "column",
|
|
714
|
+
alignItems: isUser ? "flex-end" : "flex-start",
|
|
715
|
+
gap: "8px"
|
|
717
716
|
},
|
|
718
|
-
children:
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
717
|
+
children: [
|
|
718
|
+
/* @__PURE__ */ jsx2(
|
|
719
|
+
"div",
|
|
720
|
+
{
|
|
721
|
+
style: {
|
|
722
|
+
maxWidth: "85%",
|
|
723
|
+
padding: "12px 16px",
|
|
724
|
+
backgroundColor: isUser ? theme.primaryColor : "#f5f5f5",
|
|
725
|
+
color: isUser ? "#fff" : theme.textColor,
|
|
726
|
+
borderRadius: "12px",
|
|
727
|
+
borderBottomRightRadius: isUser ? "4px" : "12px",
|
|
728
|
+
borderBottomLeftRadius: isUser ? "12px" : "4px",
|
|
729
|
+
fontSize: "14px",
|
|
730
|
+
lineHeight: 1.5,
|
|
731
|
+
whiteSpace: "pre-wrap"
|
|
732
|
+
},
|
|
733
|
+
children: message.content
|
|
734
|
+
}
|
|
735
|
+
),
|
|
736
|
+
hasQuickActions && /* @__PURE__ */ jsx2("div", { style: { display: "flex", flexWrap: "wrap", gap: "8px", maxWidth: "85%" }, children: message.quickActions.map((action) => /* @__PURE__ */ jsx2(
|
|
737
|
+
"button",
|
|
738
|
+
{
|
|
739
|
+
onClick: () => onQuickAction(action),
|
|
740
|
+
style: {
|
|
741
|
+
padding: "8px 14px",
|
|
742
|
+
backgroundColor: "#f5f5f5",
|
|
743
|
+
border: "1px solid #e5e5e5",
|
|
744
|
+
borderRadius: "20px",
|
|
745
|
+
fontSize: "13px",
|
|
746
|
+
cursor: "pointer",
|
|
747
|
+
color: theme.textColor,
|
|
748
|
+
transition: "all 0.15s"
|
|
749
|
+
},
|
|
750
|
+
onMouseOver: (e) => {
|
|
751
|
+
e.currentTarget.style.backgroundColor = `${theme.primaryColor}15`;
|
|
752
|
+
e.currentTarget.style.borderColor = theme.primaryColor;
|
|
753
|
+
},
|
|
754
|
+
onMouseOut: (e) => {
|
|
755
|
+
e.currentTarget.style.backgroundColor = "#f5f5f5";
|
|
756
|
+
e.currentTarget.style.borderColor = "#e5e5e5";
|
|
757
|
+
},
|
|
758
|
+
children: action.label
|
|
732
759
|
},
|
|
733
|
-
|
|
734
|
-
}
|
|
735
|
-
|
|
760
|
+
action.id
|
|
761
|
+
)) })
|
|
762
|
+
]
|
|
736
763
|
}
|
|
737
764
|
);
|
|
738
765
|
}
|
|
@@ -778,15 +805,15 @@ function LoadingSpinner({ size = 20 }) {
|
|
|
778
805
|
// src/hooks/useSession.ts
|
|
779
806
|
import { useState as useState3, useEffect as useEffect3, useCallback as useCallback2, useRef as useRef3 } from "react";
|
|
780
807
|
function useSession(options) {
|
|
781
|
-
const {
|
|
808
|
+
const { apiUrl, documentTypeId, sessionId, onSessionChange, onError } = options;
|
|
782
809
|
const [session, setSession] = useState3(null);
|
|
783
810
|
const [isLoading, setIsLoading] = useState3(true);
|
|
784
811
|
const [error, setError] = useState3(null);
|
|
785
812
|
const clientRef = useRef3(null);
|
|
786
813
|
const isStreamingRef = useRef3(false);
|
|
787
814
|
useEffect3(() => {
|
|
788
|
-
clientRef.current = new InformedAIClient(
|
|
789
|
-
}, [
|
|
815
|
+
clientRef.current = new InformedAIClient(apiUrl);
|
|
816
|
+
}, [apiUrl]);
|
|
790
817
|
useEffect3(() => {
|
|
791
818
|
async function initialize() {
|
|
792
819
|
if (!clientRef.current) return;
|
|
@@ -797,7 +824,8 @@ function useSession(options) {
|
|
|
797
824
|
if (sessionId) {
|
|
798
825
|
sess = await clientRef.current.getSession(sessionId);
|
|
799
826
|
} else {
|
|
800
|
-
|
|
827
|
+
const result = await clientRef.current.createSession(documentTypeId);
|
|
828
|
+
sess = result.session;
|
|
801
829
|
}
|
|
802
830
|
setSession(sess);
|
|
803
831
|
onSessionChange?.(sess);
|
|
@@ -810,7 +838,7 @@ function useSession(options) {
|
|
|
810
838
|
}
|
|
811
839
|
}
|
|
812
840
|
initialize();
|
|
813
|
-
}, [
|
|
841
|
+
}, [documentTypeId, sessionId, onSessionChange, onError]);
|
|
814
842
|
const handleSSEEvent = useCallback2((event) => {
|
|
815
843
|
if (event.type === "done" || event.type === "session_update") {
|
|
816
844
|
if (event.session) {
|
|
@@ -839,7 +867,7 @@ function useSession(options) {
|
|
|
839
867
|
isStreamingRef.current = false;
|
|
840
868
|
}
|
|
841
869
|
}, [session, handleSSEEvent, onError]);
|
|
842
|
-
const sendQuickAction = useCallback2(async (action
|
|
870
|
+
const sendQuickAction = useCallback2(async (action) => {
|
|
843
871
|
if (!clientRef.current || !session || isStreamingRef.current) return;
|
|
844
872
|
try {
|
|
845
873
|
isStreamingRef.current = true;
|
|
@@ -847,7 +875,6 @@ function useSession(options) {
|
|
|
847
875
|
const newSession = await clientRef.current.sendQuickAction(
|
|
848
876
|
session.id,
|
|
849
877
|
action,
|
|
850
|
-
payload,
|
|
851
878
|
handleSSEEvent
|
|
852
879
|
);
|
|
853
880
|
setSession(newSession);
|
|
@@ -864,9 +891,9 @@ function useSession(options) {
|
|
|
864
891
|
if (!clientRef.current || !session) return;
|
|
865
892
|
try {
|
|
866
893
|
setError(null);
|
|
867
|
-
const
|
|
868
|
-
setSession(
|
|
869
|
-
onSessionChange?.(
|
|
894
|
+
const result = await clientRef.current.applyPendingValue(session.id);
|
|
895
|
+
setSession(result.session);
|
|
896
|
+
onSessionChange?.(result.session);
|
|
870
897
|
} catch (err) {
|
|
871
898
|
const error2 = err instanceof Error ? err : new Error("Failed to apply value");
|
|
872
899
|
setError(error2);
|
|
@@ -896,68 +923,10 @@ function useSession(options) {
|
|
|
896
923
|
skipTask
|
|
897
924
|
};
|
|
898
925
|
}
|
|
899
|
-
|
|
900
|
-
// src/hooks/useDocument.ts
|
|
901
|
-
import { useState as useState4, useEffect as useEffect4, useCallback as useCallback3, useRef as useRef4 } from "react";
|
|
902
|
-
function useDocument(options) {
|
|
903
|
-
const { apiKey, apiUrl, documentId, onError } = options;
|
|
904
|
-
const [document, setDocument] = useState4(null);
|
|
905
|
-
const [documentType, setDocumentType] = useState4(null);
|
|
906
|
-
const [isLoading, setIsLoading] = useState4(true);
|
|
907
|
-
const [error, setError] = useState4(null);
|
|
908
|
-
const clientRef = useRef4(null);
|
|
909
|
-
useEffect4(() => {
|
|
910
|
-
clientRef.current = new InformedAIClient(apiKey, apiUrl);
|
|
911
|
-
}, [apiKey, apiUrl]);
|
|
912
|
-
const fetchDocument = useCallback3(async () => {
|
|
913
|
-
if (!clientRef.current) return;
|
|
914
|
-
try {
|
|
915
|
-
setIsLoading(true);
|
|
916
|
-
setError(null);
|
|
917
|
-
const doc = await clientRef.current.getDocument(documentId);
|
|
918
|
-
setDocument(doc);
|
|
919
|
-
const dt = await clientRef.current.getDocumentType(doc.documentTypeId);
|
|
920
|
-
setDocumentType(dt);
|
|
921
|
-
} catch (err) {
|
|
922
|
-
const error2 = err instanceof Error ? err : new Error("Failed to fetch document");
|
|
923
|
-
setError(error2);
|
|
924
|
-
onError?.(error2);
|
|
925
|
-
} finally {
|
|
926
|
-
setIsLoading(false);
|
|
927
|
-
}
|
|
928
|
-
}, [documentId, onError]);
|
|
929
|
-
useEffect4(() => {
|
|
930
|
-
fetchDocument();
|
|
931
|
-
}, [fetchDocument]);
|
|
932
|
-
const updateField = useCallback3(async (fieldName, value) => {
|
|
933
|
-
if (!clientRef.current || !document) return;
|
|
934
|
-
try {
|
|
935
|
-
setError(null);
|
|
936
|
-
const updatedDoc = await clientRef.current.updateDocumentField(document.id, fieldName, value);
|
|
937
|
-
setDocument(updatedDoc);
|
|
938
|
-
} catch (err) {
|
|
939
|
-
const error2 = err instanceof Error ? err : new Error("Failed to update field");
|
|
940
|
-
setError(error2);
|
|
941
|
-
onError?.(error2);
|
|
942
|
-
}
|
|
943
|
-
}, [document, onError]);
|
|
944
|
-
const refetch = useCallback3(async () => {
|
|
945
|
-
await fetchDocument();
|
|
946
|
-
}, [fetchDocument]);
|
|
947
|
-
return {
|
|
948
|
-
document,
|
|
949
|
-
documentType,
|
|
950
|
-
isLoading,
|
|
951
|
-
error,
|
|
952
|
-
updateField,
|
|
953
|
-
refetch
|
|
954
|
-
};
|
|
955
|
-
}
|
|
956
926
|
export {
|
|
957
927
|
InformedAIClient,
|
|
958
928
|
InformedAIProvider,
|
|
959
929
|
InformedAssistant,
|
|
960
|
-
useDocument,
|
|
961
930
|
useInformedAI,
|
|
962
931
|
useSession
|
|
963
932
|
};
|