@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 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
- /** API key for authentication (wsk_...) */
75
- apiKey: string;
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
- apiKey: string;
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
- documentId: string;
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(apiKey: string, apiUrl?: string);
204
+ constructor(apiUrl?: string);
207
205
  private getHeaders;
208
206
  private request;
209
- getDocument(id: string): Promise<Document>;
210
- getDocumentType(id: string): Promise<DocumentType>;
211
- updateDocumentField(documentId: string, field: string, value: unknown): Promise<Document>;
212
- createSession(documentId: string): Promise<Session>;
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 with SSE streaming
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, payload?: Record<string, unknown>, onEvent?: (event: SSEEvent) => void): Promise<Session>;
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<Session>;
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 UseDocumentReturn, type UseSessionReturn, type WidgetMessage, type WidgetTheme, useDocument, useInformedAI, useSession };
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
- /** API key for authentication (wsk_...) */
75
- apiKey: string;
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
- apiKey: string;
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
- documentId: string;
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(apiKey: string, apiUrl?: string);
204
+ constructor(apiUrl?: string);
207
205
  private getHeaders;
208
206
  private request;
209
- getDocument(id: string): Promise<Document>;
210
- getDocumentType(id: string): Promise<DocumentType>;
211
- updateDocumentField(documentId: string, field: string, value: unknown): Promise<Document>;
212
- createSession(documentId: string): Promise<Session>;
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 with SSE streaming
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, payload?: Record<string, unknown>, onEvent?: (event: SSEEvent) => void): Promise<Session>;
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<Session>;
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 UseDocumentReturn, type UseSessionReturn, type WidgetMessage, type WidgetTheme, useDocument, useInformedAI, useSession };
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(apiKey, apiUrl) {
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
- // Document Operations
66
+ // Widget Session Operations (keyless)
70
67
  // ========================================================================
71
- async getDocument(id) {
72
- return this.request(`/documents/${id}`);
73
- }
74
- async getDocumentType(id) {
75
- return this.request(`/document-types/${id}`);
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({ documentId })
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 with SSE streaming
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, payload, onEvent) {
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, payload })
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
- let finalSession = null;
127
- await this.processSSEStream(response, (event) => {
128
- onEvent?.(event);
129
- if (event.session) {
130
- finalSession = event.session;
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
- if (!finalSession) {
134
- throw new Error("No session returned from quick action");
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.apiKey, config.apiUrl);
215
- }, [config.apiKey, config.apiUrl]);
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
- sess = await clientRef.current.createSession(config.documentId);
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.documentId, config.sessionId]);
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, payload) => {
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 activeTask = session.activeTask;
309
- const pendingValue = activeTask ? session.taskStates[activeTask]?.pendingValue : void 0;
310
- const newSession = await clientRef.current.applyPendingValue(session.id);
311
- setSession(newSession);
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
- if (message.type === "quick_actions" && message.quickActions) {
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.jsx)(
738
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
743
739
  "div",
744
740
  {
745
741
  style: {
746
742
  display: "flex",
747
- justifyContent: isUser ? "flex-end" : "flex-start"
743
+ flexDirection: "column",
744
+ alignItems: isUser ? "flex-end" : "flex-start",
745
+ gap: "8px"
748
746
  },
749
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
750
- "div",
751
- {
752
- style: {
753
- maxWidth: "85%",
754
- padding: "12px 16px",
755
- backgroundColor: isUser ? theme.primaryColor : "#f5f5f5",
756
- color: isUser ? "#fff" : theme.textColor,
757
- borderRadius: "12px",
758
- borderBottomRightRadius: isUser ? "4px" : "12px",
759
- borderBottomLeftRadius: isUser ? "12px" : "4px",
760
- fontSize: "14px",
761
- lineHeight: 1.5,
762
- whiteSpace: "pre-wrap"
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
- children: message.content
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 { apiKey, apiUrl, documentId, sessionId, onSessionChange, onError } = options;
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(apiKey, apiUrl);
820
- }, [apiKey, apiUrl]);
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
- sess = await clientRef.current.createSession(documentId);
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
- }, [documentId, sessionId, onSessionChange, onError]);
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, payload) => {
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 newSession = await clientRef.current.applyPendingValue(session.id);
899
- setSession(newSession);
900
- onSessionChange?.(newSession);
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(apiKey, apiUrl) {
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
- // Document Operations
36
+ // Widget Session Operations (keyless)
39
37
  // ========================================================================
40
- async getDocument(id) {
41
- return this.request(`/documents/${id}`);
42
- }
43
- async getDocumentType(id) {
44
- return this.request(`/document-types/${id}`);
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({ documentId })
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 with SSE streaming
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, payload, onEvent) {
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, payload })
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
- let finalSession = null;
96
- await this.processSSEStream(response, (event) => {
97
- onEvent?.(event);
98
- if (event.session) {
99
- finalSession = event.session;
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
- if (!finalSession) {
103
- throw new Error("No session returned from quick action");
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.apiKey, config.apiUrl);
184
- }, [config.apiKey, config.apiUrl]);
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
- sess = await clientRef.current.createSession(config.documentId);
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.documentId, config.sessionId]);
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, payload) => {
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 activeTask = session.activeTask;
278
- const pendingValue = activeTask ? session.taskStates[activeTask]?.pendingValue : void 0;
279
- const newSession = await clientRef.current.applyPendingValue(session.id);
280
- setSession(newSession);
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
- if (message.type === "quick_actions" && message.quickActions) {
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__ */ jsx2(
708
+ return /* @__PURE__ */ jsxs(
712
709
  "div",
713
710
  {
714
711
  style: {
715
712
  display: "flex",
716
- justifyContent: isUser ? "flex-end" : "flex-start"
713
+ flexDirection: "column",
714
+ alignItems: isUser ? "flex-end" : "flex-start",
715
+ gap: "8px"
717
716
  },
718
- children: /* @__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"
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
- children: message.content
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 { apiKey, apiUrl, documentId, sessionId, onSessionChange, onError } = options;
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(apiKey, apiUrl);
789
- }, [apiKey, apiUrl]);
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
- sess = await clientRef.current.createSession(documentId);
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
- }, [documentId, sessionId, onSessionChange, onError]);
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, payload) => {
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 newSession = await clientRef.current.applyPendingValue(session.id);
868
- setSession(newSession);
869
- onSessionChange?.(newSession);
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
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@informedai/react",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "React SDK for InformedAI Assistant - AI-powered content creation widget",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",