@informedai/react 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -71,12 +71,10 @@ interface Document {
71
71
  };
72
72
  }
73
73
  interface InformedAssistantConfig {
74
- /** API key for authentication (wsk_...) */
75
- apiKey: string;
74
+ /** Document Type ID - identifies which form schema to use */
75
+ documentTypeId: string;
76
76
  /** API base URL (defaults to https://api.informedassistant.ai/api/v1) */
77
77
  apiUrl?: string;
78
- /** Document ID to work with */
79
- documentId: string;
80
78
  /** Optional: Existing session ID to resume */
81
79
  sessionId?: string;
82
80
  /** Callback when a field value is applied */
@@ -119,14 +117,6 @@ interface UseSessionReturn {
119
117
  applyPendingValue: () => Promise<void>;
120
118
  skipTask: () => Promise<void>;
121
119
  }
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
120
 
131
121
  interface InformedAssistantProps extends InformedAssistantConfig {
132
122
  /** Additional CSS class name */
@@ -173,62 +163,74 @@ declare function InformedAIProvider({ config, children }: InformedAIProviderProp
173
163
  */
174
164
 
175
165
  interface UseSessionOptions {
176
- apiKey: string;
166
+ /** Document Type ID - identifies which form schema to use */
167
+ documentTypeId: string;
168
+ /** API base URL (defaults to https://api.informedassistant.ai/api/v1) */
177
169
  apiUrl?: string;
178
- documentId: string;
170
+ /** Optional: Existing session ID to resume */
179
171
  sessionId?: string;
172
+ /** Callback when session state changes */
180
173
  onSessionChange?: (session: Session) => void;
174
+ /** Callback when an error occurs */
181
175
  onError?: (error: Error) => void;
182
176
  }
183
177
  declare function useSession(options: UseSessionOptions): UseSessionReturn;
184
178
 
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
179
  /**
199
180
  * InformedAI API Client
200
181
  * Handles all communication with the InformedAI backend
182
+ *
183
+ * Uses keyless widget endpoints with domain-based authentication.
201
184
  */
202
185
 
186
+ interface CreateSessionResponse {
187
+ session: Session;
188
+ document: Document;
189
+ documentType: {
190
+ id: string;
191
+ name: string;
192
+ displayName: string;
193
+ schema: unknown;
194
+ };
195
+ }
196
+ interface ApplyResponse {
197
+ session: Session;
198
+ appliedField: string;
199
+ appliedValue: unknown;
200
+ }
203
201
  declare class InformedAIClient {
204
- private apiKey;
205
202
  private apiUrl;
206
- constructor(apiKey: string, apiUrl?: string);
203
+ constructor(apiUrl?: string);
207
204
  private getHeaders;
208
205
  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>;
206
+ /**
207
+ * Create a new session for a document type.
208
+ * This automatically creates a document with default values.
209
+ */
210
+ createSession(documentTypeId: string): Promise<CreateSessionResponse>;
211
+ /**
212
+ * Get an existing session.
213
+ */
213
214
  getSession(id: string): Promise<Session>;
214
- deleteSession(id: string): Promise<void>;
215
215
  /**
216
- * Send a message to the session with SSE streaming
216
+ * Send a message to the session with SSE streaming.
217
217
  */
218
218
  sendMessage(sessionId: string, message: string, onEvent: (event: SSEEvent) => void): Promise<void>;
219
219
  /**
220
- * Send a quick action to the session with SSE streaming
220
+ * Send a quick action to the session.
221
+ * For actions that trigger AI (task_action:*), returns SSE stream.
222
+ * For other actions (select_task:*, resume_task:*), returns session directly.
221
223
  */
222
- sendQuickAction(sessionId: string, action: string, payload?: Record<string, unknown>, onEvent?: (event: SSEEvent) => void): Promise<Session>;
224
+ sendQuickAction(sessionId: string, action: string, onEvent?: (event: SSEEvent) => void): Promise<Session>;
223
225
  /**
224
- * Apply the pending value for the active task
226
+ * Apply the pending value for the active task.
225
227
  */
226
- applyPendingValue(sessionId: string): Promise<Session>;
228
+ applyPendingValue(sessionId: string): Promise<ApplyResponse>;
227
229
  /**
228
- * Skip the active task
230
+ * Skip the active task.
229
231
  */
230
232
  skipTask(sessionId: string): Promise<Session>;
231
233
  private processSSEStream;
232
234
  }
233
235
 
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 };
236
+ 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
@@ -71,12 +71,10 @@ interface Document {
71
71
  };
72
72
  }
73
73
  interface InformedAssistantConfig {
74
- /** API key for authentication (wsk_...) */
75
- apiKey: string;
74
+ /** Document Type ID - identifies which form schema to use */
75
+ documentTypeId: string;
76
76
  /** API base URL (defaults to https://api.informedassistant.ai/api/v1) */
77
77
  apiUrl?: string;
78
- /** Document ID to work with */
79
- documentId: string;
80
78
  /** Optional: Existing session ID to resume */
81
79
  sessionId?: string;
82
80
  /** Callback when a field value is applied */
@@ -119,14 +117,6 @@ interface UseSessionReturn {
119
117
  applyPendingValue: () => Promise<void>;
120
118
  skipTask: () => Promise<void>;
121
119
  }
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
120
 
131
121
  interface InformedAssistantProps extends InformedAssistantConfig {
132
122
  /** Additional CSS class name */
@@ -173,62 +163,74 @@ declare function InformedAIProvider({ config, children }: InformedAIProviderProp
173
163
  */
174
164
 
175
165
  interface UseSessionOptions {
176
- apiKey: string;
166
+ /** Document Type ID - identifies which form schema to use */
167
+ documentTypeId: string;
168
+ /** API base URL (defaults to https://api.informedassistant.ai/api/v1) */
177
169
  apiUrl?: string;
178
- documentId: string;
170
+ /** Optional: Existing session ID to resume */
179
171
  sessionId?: string;
172
+ /** Callback when session state changes */
180
173
  onSessionChange?: (session: Session) => void;
174
+ /** Callback when an error occurs */
181
175
  onError?: (error: Error) => void;
182
176
  }
183
177
  declare function useSession(options: UseSessionOptions): UseSessionReturn;
184
178
 
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
179
  /**
199
180
  * InformedAI API Client
200
181
  * Handles all communication with the InformedAI backend
182
+ *
183
+ * Uses keyless widget endpoints with domain-based authentication.
201
184
  */
202
185
 
186
+ interface CreateSessionResponse {
187
+ session: Session;
188
+ document: Document;
189
+ documentType: {
190
+ id: string;
191
+ name: string;
192
+ displayName: string;
193
+ schema: unknown;
194
+ };
195
+ }
196
+ interface ApplyResponse {
197
+ session: Session;
198
+ appliedField: string;
199
+ appliedValue: unknown;
200
+ }
203
201
  declare class InformedAIClient {
204
- private apiKey;
205
202
  private apiUrl;
206
- constructor(apiKey: string, apiUrl?: string);
203
+ constructor(apiUrl?: string);
207
204
  private getHeaders;
208
205
  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>;
206
+ /**
207
+ * Create a new session for a document type.
208
+ * This automatically creates a document with default values.
209
+ */
210
+ createSession(documentTypeId: string): Promise<CreateSessionResponse>;
211
+ /**
212
+ * Get an existing session.
213
+ */
213
214
  getSession(id: string): Promise<Session>;
214
- deleteSession(id: string): Promise<void>;
215
215
  /**
216
- * Send a message to the session with SSE streaming
216
+ * Send a message to the session with SSE streaming.
217
217
  */
218
218
  sendMessage(sessionId: string, message: string, onEvent: (event: SSEEvent) => void): Promise<void>;
219
219
  /**
220
- * Send a quick action to the session with SSE streaming
220
+ * Send a quick action to the session.
221
+ * For actions that trigger AI (task_action:*), returns SSE stream.
222
+ * For other actions (select_task:*, resume_task:*), returns session directly.
221
223
  */
222
- sendQuickAction(sessionId: string, action: string, payload?: Record<string, unknown>, onEvent?: (event: SSEEvent) => void): Promise<Session>;
224
+ sendQuickAction(sessionId: string, action: string, onEvent?: (event: SSEEvent) => void): Promise<Session>;
223
225
  /**
224
- * Apply the pending value for the active task
226
+ * Apply the pending value for the active task.
225
227
  */
226
- applyPendingValue(sessionId: string): Promise<Session>;
228
+ applyPendingValue(sessionId: string): Promise<ApplyResponse>;
227
229
  /**
228
- * Skip the active task
230
+ * Skip the active task.
229
231
  */
230
232
  skipTask(sessionId: string): Promise<Session>;
231
233
  private processSSEStream;
232
234
  }
233
235
 
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 };
236
+ 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);
@@ -809,15 +804,15 @@ function LoadingSpinner({ size = 20 }) {
809
804
  // src/hooks/useSession.ts
810
805
  var import_react3 = require("react");
811
806
  function useSession(options) {
812
- const { apiKey, apiUrl, documentId, sessionId, onSessionChange, onError } = options;
807
+ const { apiUrl, documentTypeId, sessionId, onSessionChange, onError } = options;
813
808
  const [session, setSession] = (0, import_react3.useState)(null);
814
809
  const [isLoading, setIsLoading] = (0, import_react3.useState)(true);
815
810
  const [error, setError] = (0, import_react3.useState)(null);
816
811
  const clientRef = (0, import_react3.useRef)(null);
817
812
  const isStreamingRef = (0, import_react3.useRef)(false);
818
813
  (0, import_react3.useEffect)(() => {
819
- clientRef.current = new InformedAIClient(apiKey, apiUrl);
820
- }, [apiKey, apiUrl]);
814
+ clientRef.current = new InformedAIClient(apiUrl);
815
+ }, [apiUrl]);
821
816
  (0, import_react3.useEffect)(() => {
822
817
  async function initialize() {
823
818
  if (!clientRef.current) return;
@@ -828,7 +823,8 @@ function useSession(options) {
828
823
  if (sessionId) {
829
824
  sess = await clientRef.current.getSession(sessionId);
830
825
  } else {
831
- sess = await clientRef.current.createSession(documentId);
826
+ const result = await clientRef.current.createSession(documentTypeId);
827
+ sess = result.session;
832
828
  }
833
829
  setSession(sess);
834
830
  onSessionChange?.(sess);
@@ -841,7 +837,7 @@ function useSession(options) {
841
837
  }
842
838
  }
843
839
  initialize();
844
- }, [documentId, sessionId, onSessionChange, onError]);
840
+ }, [documentTypeId, sessionId, onSessionChange, onError]);
845
841
  const handleSSEEvent = (0, import_react3.useCallback)((event) => {
846
842
  if (event.type === "done" || event.type === "session_update") {
847
843
  if (event.session) {
@@ -870,7 +866,7 @@ function useSession(options) {
870
866
  isStreamingRef.current = false;
871
867
  }
872
868
  }, [session, handleSSEEvent, onError]);
873
- const sendQuickAction = (0, import_react3.useCallback)(async (action, payload) => {
869
+ const sendQuickAction = (0, import_react3.useCallback)(async (action) => {
874
870
  if (!clientRef.current || !session || isStreamingRef.current) return;
875
871
  try {
876
872
  isStreamingRef.current = true;
@@ -878,7 +874,6 @@ function useSession(options) {
878
874
  const newSession = await clientRef.current.sendQuickAction(
879
875
  session.id,
880
876
  action,
881
- payload,
882
877
  handleSSEEvent
883
878
  );
884
879
  setSession(newSession);
@@ -895,9 +890,9 @@ function useSession(options) {
895
890
  if (!clientRef.current || !session) return;
896
891
  try {
897
892
  setError(null);
898
- const newSession = await clientRef.current.applyPendingValue(session.id);
899
- setSession(newSession);
900
- onSessionChange?.(newSession);
893
+ const result = await clientRef.current.applyPendingValue(session.id);
894
+ setSession(result.session);
895
+ onSessionChange?.(result.session);
901
896
  } catch (err) {
902
897
  const error2 = err instanceof Error ? err : new Error("Failed to apply value");
903
898
  setError(error2);
@@ -927,69 +922,11 @@ function useSession(options) {
927
922
  skipTask
928
923
  };
929
924
  }
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
925
  // Annotate the CommonJS export names for ESM import in node:
988
926
  0 && (module.exports = {
989
927
  InformedAIClient,
990
928
  InformedAIProvider,
991
929
  InformedAssistant,
992
- useDocument,
993
930
  useInformedAI,
994
931
  useSession
995
932
  });
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);
@@ -778,15 +774,15 @@ function LoadingSpinner({ size = 20 }) {
778
774
  // src/hooks/useSession.ts
779
775
  import { useState as useState3, useEffect as useEffect3, useCallback as useCallback2, useRef as useRef3 } from "react";
780
776
  function useSession(options) {
781
- const { apiKey, apiUrl, documentId, sessionId, onSessionChange, onError } = options;
777
+ const { apiUrl, documentTypeId, sessionId, onSessionChange, onError } = options;
782
778
  const [session, setSession] = useState3(null);
783
779
  const [isLoading, setIsLoading] = useState3(true);
784
780
  const [error, setError] = useState3(null);
785
781
  const clientRef = useRef3(null);
786
782
  const isStreamingRef = useRef3(false);
787
783
  useEffect3(() => {
788
- clientRef.current = new InformedAIClient(apiKey, apiUrl);
789
- }, [apiKey, apiUrl]);
784
+ clientRef.current = new InformedAIClient(apiUrl);
785
+ }, [apiUrl]);
790
786
  useEffect3(() => {
791
787
  async function initialize() {
792
788
  if (!clientRef.current) return;
@@ -797,7 +793,8 @@ function useSession(options) {
797
793
  if (sessionId) {
798
794
  sess = await clientRef.current.getSession(sessionId);
799
795
  } else {
800
- sess = await clientRef.current.createSession(documentId);
796
+ const result = await clientRef.current.createSession(documentTypeId);
797
+ sess = result.session;
801
798
  }
802
799
  setSession(sess);
803
800
  onSessionChange?.(sess);
@@ -810,7 +807,7 @@ function useSession(options) {
810
807
  }
811
808
  }
812
809
  initialize();
813
- }, [documentId, sessionId, onSessionChange, onError]);
810
+ }, [documentTypeId, sessionId, onSessionChange, onError]);
814
811
  const handleSSEEvent = useCallback2((event) => {
815
812
  if (event.type === "done" || event.type === "session_update") {
816
813
  if (event.session) {
@@ -839,7 +836,7 @@ function useSession(options) {
839
836
  isStreamingRef.current = false;
840
837
  }
841
838
  }, [session, handleSSEEvent, onError]);
842
- const sendQuickAction = useCallback2(async (action, payload) => {
839
+ const sendQuickAction = useCallback2(async (action) => {
843
840
  if (!clientRef.current || !session || isStreamingRef.current) return;
844
841
  try {
845
842
  isStreamingRef.current = true;
@@ -847,7 +844,6 @@ function useSession(options) {
847
844
  const newSession = await clientRef.current.sendQuickAction(
848
845
  session.id,
849
846
  action,
850
- payload,
851
847
  handleSSEEvent
852
848
  );
853
849
  setSession(newSession);
@@ -864,9 +860,9 @@ function useSession(options) {
864
860
  if (!clientRef.current || !session) return;
865
861
  try {
866
862
  setError(null);
867
- const newSession = await clientRef.current.applyPendingValue(session.id);
868
- setSession(newSession);
869
- onSessionChange?.(newSession);
863
+ const result = await clientRef.current.applyPendingValue(session.id);
864
+ setSession(result.session);
865
+ onSessionChange?.(result.session);
870
866
  } catch (err) {
871
867
  const error2 = err instanceof Error ? err : new Error("Failed to apply value");
872
868
  setError(error2);
@@ -896,68 +892,10 @@ function useSession(options) {
896
892
  skipTask
897
893
  };
898
894
  }
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
895
  export {
957
896
  InformedAIClient,
958
897
  InformedAIProvider,
959
898
  InformedAssistant,
960
- useDocument,
961
899
  useInformedAI,
962
900
  useSession
963
901
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@informedai/react",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
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",